home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / comm / amigatcp.5 < prev    next >
Text File  |  1989-03-18  |  64KB  |  2,823 lines

  1. Path: xanth!ukma!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i084:  amigatcp - tcp/ip for the amiga, Part05/06
  5. Message-ID: <12332@swan.ulowell.edu>
  6. Date: 17 Mar 89 23:20:02 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2812
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: rminnich@super.org (Ronald G. Minnich)
  12. Posting-number: Volume 89, Issue 84
  13. Archive-name: comm/amigatcp.5
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    amiga.c
  23. #    amigadev.c
  24. #    iproute.c
  25. #    telnetp.c
  26. # This archive created: Fri Mar 17 17:58:48 1989
  27. cat << \SHAR_EOF > amiga.c
  28. /*
  29.  *  Modifications to existing pc.c module are --
  30.  *
  31.  *  Copyright (c) 1987
  32.  *  Louis A. Mamakos
  33.  *
  34.  *  This work, or any derivations thereof may be used for non-commercial
  35.  *  purposes only.  So there.
  36.  */
  37.  
  38. /* OS- and machine-dependent stuff for the Commodore-Amiga 1000 */
  39.  
  40. #define    AMIGAVERSION    "3"
  41.  
  42. #include <exec/types.h>
  43. #include <functions.h>        
  44. /* for Manx Aztec C, get func returns */
  45. #include <exec/nodes.h>
  46. #include <exec/lists.h>
  47. #include <exec/ports.h>
  48. #include <exec/devices.h>
  49. #include <exec/io.h>
  50.  
  51. #include <devices/console.h>
  52. #include <devices/serial.h>
  53. #include <devices/timer.h>
  54. #include <libraries/dos.h>
  55. #include <libraries/dosextens.h>
  56. #include <intuition/intuition.h>
  57.  
  58. #include <stdio.h>
  59. #include "machdep.h"
  60. #include "amiga.h"
  61. #include "mbuf.h"
  62. #include "internet.h"
  63. #include "iface.h"
  64. #include "cmdparse.h"
  65. #include "slip.h"
  66. #include "timer.h"
  67. #include "netuser.h"
  68. #include "ip.h"
  69. #include "tcp.h"
  70. #ifdef    TRACE
  71. #include "trace.h"
  72. #endif
  73.  
  74. static char *copyright_notice[2] = {
  75.     "AMIGA port of KA9Q TCP/IP (C) Copyright 1987 Louis A. Mamakos\r\n",
  76.     "for non-commercial, non-profic use only\r\n"};
  77.  
  78. struct asy asy[ASY_MAX];
  79.  
  80. void *malloc();
  81.  
  82. void setiss();
  83.  
  84. /* Interface list header */
  85. struct interface *ifaces;
  86.  
  87. struct IntuitionBase *IntuitionBase;
  88. static char banner[80];
  89. static struct NewWindow nw = {
  90.     0, 0, 640, 200,        /* left, top, (max) width, (max) height */
  91.     0, 1,            /* detail pen, block pen */
  92.     0,            /* IDCMP flags */
  93.     SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING |
  94.         SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH,    /* window flags */
  95.     NULL, NULL,        /* gadget, checkmark */
  96.     (UBYTE *)&banner[0],    /* title of window */
  97.     NULL, NULL,        /* screen, bitmap */
  98.     200, 50, -1, -1,    /* sizing limits */
  99.     WBENCHSCREEN,        /* on the workbench */
  100. };
  101.  
  102. APTR    oldwindowptr;
  103. struct Process *mytask;
  104.  
  105. struct MsgPort *keyboard, *consinp, *consoutp, *serinp, *seroutp,
  106.               *timerp;
  107. struct IOExtSer serin, serout;
  108. struct IOStdReq consin, consout;
  109. struct timerequest tr;
  110. struct Window *win;
  111.  
  112. char InputCharacter;
  113.  
  114. int timeropen, serialopen;
  115. #ifdef AMIGADEVDRV
  116. int DeviceSignal;
  117. #endif
  118. struct timer worktimer;        /* this is NOT a timer.device timer */
  119. void worker();
  120. #ifdef LATTICE
  121. extern struct { short error; char *msg; } os_errlist[];
  122. extern int _OSERR, os_nerr;
  123. #endif
  124. static
  125. clean(why)
  126.     char *why;
  127. {
  128.     int i;
  129.  
  130. #ifdef AMIGADEVDRV
  131.     if (DeviceSignal >= 0)
  132.         FreeSignal(DeviceSignal);
  133. #endif
  134.     if (timeropen)
  135.         CloseDevice(&tr);
  136.     if (serialopen)
  137.         CloseDevice(&serin);
  138.     if (win)
  139.         CloseWindow(win);
  140.     if (consinp)
  141.         DeletePort(consinp);
  142.     if (consoutp)
  143.         DeletePort(consoutp);
  144.     if (serinp)
  145.         DeletePort(serinp);
  146.     if (seroutp)
  147.         DeletePort(seroutp);
  148.     if (timerp)
  149.         DeletePort(timerp);
  150.  
  151.     mytask->pr_WindowPtr = oldwindowptr;
  152.  
  153.     if (why) {
  154.            myoserr(why);
  155.     }
  156.     exit(0);
  157. }
  158. myoserr(why)
  159. char *why;
  160. {
  161.   int i;
  162.         fprintf(stderr, "%s: ", why); 
  163. #ifdef LATTICE
  164.         fprintf(stderr, "%d: ", _OSERR);
  165.  
  166.         for(i = 0; os_errlist[i].error < os_nerr; i++)
  167.           if (os_errlist[i].error == _OSERR)
  168.             fprintf(stderr, os_errlist[i].msg);
  169. #endif
  170.         fprintf(stderr, "\r\n");
  171. }
  172. /* Called at startup time to set up console I/O, memory heap */
  173. ioinit()
  174. {
  175.     extern char major_rev[], minor_rev[];
  176.     struct Screen *scr;
  177.  
  178.     mytask = (struct Process *) FindTask((char *) NULL);
  179.     oldwindowptr = mytask->pr_WindowPtr;
  180.     mytask->pr_WindowPtr = (APTR) -1;    /* disable DOS requestors */
  181.  
  182.     if ((IntuitionBase = (struct IntuitionBase *)
  183.        OpenLibrary("intuition.library", 33L)) == NULL)
  184.         clean("No intuition: Version 1.2 of Amiga Systems Software required");
  185.  
  186.     sprintf(banner,
  187. #ifdef    AMIGADEVDRV
  188.     "KA9Q Internet Protocol Package, v%s.%s (Amiga version %sD)",
  189. #else
  190.     "KA9Q Internet Protocol Package, v%s.%s (Amiga version %s)",
  191. #endif
  192.         major_rev, minor_rev, AMIGAVERSION);
  193.  
  194.     /*
  195.      *  Try to determine the size of the workbench screen
  196.      */
  197.     scr = malloc(sizeof(struct Screen));
  198.     if (scr==NULL)
  199.         clean("Can't alloc screen");
  200.  
  201.     if (GetScreenData(scr, (ULONG) sizeof(struct Screen),
  202.               WBENCHSCREEN, NULL) == TRUE) {
  203.         nw.Width = scr->Width;
  204.         nw.Height = scr->Height-20;
  205.         nw.TopEdge = 19;
  206.     } else
  207.         fprintf(stderr, "Can't GetScreenData()\n");
  208.  
  209.     free((char *)scr);
  210.     if ((win = OpenWindow(&nw)) == NULL)
  211.         clean("Can't open window");
  212.  
  213.     if ((consinp = CreatePort("net:console in", 0L)) == NULL)
  214.         clean("Can't create console port");
  215.  
  216.     if ((consoutp = CreatePort("net:console out", 0L)) == NULL)
  217.         clean("Can't create console port");
  218.  
  219.     if ((timerp = CreatePort("net:timer", 0L)) == NULL)
  220.         clean("Can't create timer port");
  221.  
  222.     consin.io_Data = (APTR) win;
  223.     consin.io_Length = sizeof(struct Window);
  224.  
  225.     if (OpenDevice("console.device", 0L, &consin, 0L) != 0L)
  226.         clean("Can't open console device");
  227.  
  228.     consout = consin;
  229.  
  230.     consin.io_Message.mn_ReplyPort = consinp;
  231.     consin.io_Length = 1;
  232.     consin.io_Data = (APTR) &InputCharacter;
  233.     consin.io_Command = CMD_READ;
  234.     SendIO(&consin);
  235.     consout.io_Message.mn_ReplyPort = consoutp;
  236.     consout.io_Command = CMD_WRITE;
  237.  
  238.     /* create and start up timer */
  239.     tr.tr_node.io_Message.mn_ReplyPort = timerp;
  240.     if (OpenDevice("timer.device", UNIT_VBLANK, &tr, 0L) != 0L)
  241.         clean("Can't open timer");
  242. #ifdef AMIGADEVDRV
  243.     if ((DeviceSignal = AllocSignal(-1)) == -1)
  244.       clean("Can't allocate device signal");
  245. #endif
  246.     timeropen++;
  247.     tr.tr_node.io_Command = TR_GETSYSTIME;
  248.     DoIO(&tr);
  249. #ifdef    DEBUG
  250.     printf("System time is %ld\n", tr.tr_time.tv_secs);
  251. #endif
  252.     setiss(tr.tr_time.tv_secs);
  253.     tr.tr_node.io_Command = TR_ADDREQUEST;
  254.     tr.tr_time.tv_secs = 0;
  255.     tr.tr_time.tv_micro = MSPTICK*1000L;    /* convert to microseconds */
  256.     SendIO(&tr);
  257.  
  258.     set_timer(&worktimer, 1500);    /* set for 1.5 seconds */
  259.     worktimer.func = worker;
  260. #ifdef    AMIGADEVDRV
  261.     DriverInit();            /* install internet.device driver */
  262. #endif
  263.     start_timer(&worktimer);
  264. }
  265.  
  266. /* Called just before exiting to restore console state */
  267. iostop()
  268. {
  269.     while(ifaces != NULLIF){
  270.         if(ifaces->stop != NULLFP)
  271.             (*ifaces->stop)(ifaces);
  272.         ifaces = ifaces->next;
  273.     }
  274. #ifdef    AMIGADEVDRV
  275.     DriverShutdown();
  276. #endif
  277.     clean((char *)0);
  278. }
  279.  
  280. #define    BUFMAXCNT    150
  281. static char conbuf[BUFMAXCNT];
  282. static int concnt = 0;
  283.  
  284. int
  285. amigaputchar(c)
  286.     char c;
  287. {
  288.     conbuf[concnt++] = c;
  289.     if ((c == '\n') || (concnt == BUFMAXCNT))
  290.         amigaflush();
  291.     return c;
  292. }
  293.  
  294. amigaflush()
  295. {
  296.     if (concnt == 0)
  297.         return;
  298.     consout.io_Data = (APTR) conbuf;
  299.     consout.io_Length = concnt;
  300.     consout.io_Command = CMD_WRITE;
  301.     DoIO(&consout);
  302.     concnt = 0;
  303. }
  304.     
  305. /*
  306.  *  Begin terrible, horrible hack.  All output should be printed upon (into?)
  307.  *  the window we opened before.  Here goes nothing...
  308.  */
  309. void
  310. printf(a, b, c, d, e, f, g, h, i, j, k)
  311.     char *a;
  312.     int b, c, d, e, f, g, h, i, j, k;
  313. {
  314.     if (concnt)
  315.         amigaflush();
  316.  
  317.     sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k);
  318.     consout.io_Data = (APTR) conbuf;
  319.     consout.io_Length = strlen(conbuf);
  320.     consout.io_Command = CMD_WRITE;
  321.     DoIO(&consout);        /* no use in doing this async */
  322. }
  323.  
  324.     
  325. /* check active connections and update titles */
  326. void
  327. check_connections()
  328. {
  329.     extern struct tcb *tcbs[NTCB];
  330.     register struct tcb *tcb;
  331.     register int i;
  332.     int newlisten, newopn;
  333.     static int listen = -1, opn = -1;
  334.     static msg[80];
  335.  
  336.     newlisten = newopn = 0;
  337.  
  338.     for(i=0; i<NTCB; i++)
  339.         for(tcb=tcbs[i]; tcb != NULLTCB; tcb = tcb->next)
  340.             if (tcb->state == LISTEN)
  341.                 newlisten++;
  342.             else
  343.                 newopn++;
  344.  
  345.     if (newlisten != listen || newopn != opn) {
  346.         listen = newlisten;
  347.         opn = newopn;
  348.         sprintf(msg,
  349.        "Amiga Port by WA3YMH (TCP: listen: %d   open: %d)", listen, opn);
  350.         SetWindowTitles(win, -1L, msg);
  351.     }
  352. }
  353.  
  354. /* called every second or so */
  355. void
  356. worker()
  357. {
  358.     check_connections();
  359.     start_timer(&worktimer);
  360. }
  361.  
  362. #if    0
  363. /* processes any messages that Intuition sends us */
  364. void
  365. Do_Intuition_Message(m)
  366.     register struct IntuiMessage *m;
  367. {
  368.     ULONG class;
  369.     USHORT code, qualifier;
  370.  
  371.     class = m->Class;
  372.     code = m->Code;
  373.     qualifier = m->Qualifier;
  374.     ReplyMsg((struct Message *) m);       /* reply msg back to Intuition */
  375.     switch (class) {
  376.     case INTUITICKS:
  377.         check_connections();        
  378.         break;
  379.     }
  380. }
  381. #endif
  382.  
  383.     
  384. /*
  385.  * wait for something to happen
  386.  */
  387. eihalt()
  388. {
  389.     register struct IntuiMessage *msg;
  390.     static ULONG mask = 0;
  391.  
  392.     if (mask == 0L)
  393.         mask =     1L << consinp->mp_SigBit |
  394.             1L << serinp->mp_SigBit |
  395.             1L << timerp->mp_SigBit |
  396. #ifdef AMIGDEVDRV
  397.             1L << DeviceSignal    |
  398. #endif
  399. #if    0
  400.             1L << win->UserPort->mp_SigBit |
  401. #endif
  402.             1L << seroutp->mp_SigBit;
  403.  
  404.     (void) Wait(mask);
  405. #if    0
  406.     while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
  407.         Do_Intuition_Message(msg);
  408. #endif
  409. }
  410.  
  411. /* checks the time then ticks and updates ISS */
  412. void
  413. check_time()
  414. {
  415.     int32 iss();
  416.  
  417.     if (CheckIO(&tr)) {
  418.         WaitIO(&tr);
  419.         (void) GetMsg(timerp);
  420.         tick();
  421.         (void)iss();
  422.         tr.tr_time.tv_secs = 0;
  423.         tr.tr_time.tv_micro = MSPTICK*1000L;
  424.                     /* convert to microseconds */
  425.         SendIO(&tr);
  426.     }
  427. }
  428.  
  429. /* Initialize asynch port "dev" */
  430.  
  431.  
  432. /*
  433.  *  We will make the bold and rash assumption that the asy link will be used
  434.  *  for slip and slip-like stuff.  That is, we assume that there is an
  435.  *  an end-of-frame character that we can have the serial.device driver look
  436.  *  for.  Thus, we can fire up a single I/O request and have the whole frame
  437.  *  come back at once.
  438.  */
  439. int
  440. asy_init(dev, bufsize)
  441. int16 dev;
  442. unsigned bufsize;
  443. {
  444.     char serinitstr[1];
  445.     int serinitlen;
  446.  
  447.     serinitstr[0] = FR_END;    /* initialize initialization string to a */
  448.     serinitlen = 1;        /* frame end to flush receiver */
  449.  
  450.     if (serialopen) {
  451.         printf("\namiga: Error - serial device already open.\n");
  452.         return 0;
  453.     }
  454.     if ((serinp = CreatePort("net:serin", 0L)) == NULL)
  455.         clean("Can't create serial input port");
  456.  
  457.     if ((seroutp = CreatePort("net:serout", 0L)) == NULL)
  458.         clean("Can't create serial output port");
  459.  
  460.     /*
  461.      * Open serial device.
  462.      */
  463.     serin.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;  /* ? */
  464.     serin.io_Status = 0;
  465.     serin.io_RBufLen = bufsize;
  466.     asy[dev].speed = serin.io_Baud = 2400;    /* default speed */
  467.     if (OpenDevice("serial.device", 0L, &serin, 0L) != 0L)
  468.         clean("Can't open serial device");
  469.     serialopen++;
  470.     serin.IOSer.io_Message.mn_ReplyPort = serinp;
  471.     serout = serin;
  472.     serout.IOSer.io_Message.mn_ReplyPort = seroutp;
  473.     asy[dev].buflen = bufsize;
  474.     /* alloc input buffer */
  475.     if((asy[dev].input_buffer = malloc(asy[dev].buflen)) == NULL)
  476.         clean("Can't allocate serial input buf");
  477.     serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
  478.     serin.IOSer.io_Length = asy[dev].buflen;
  479.     asy[dev].input_len = 0;        /* clear input buffer */
  480.     serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
  481.     serin.IOSer.io_Flags = 0;
  482.     SendIO(&serin);
  483.     serout.IOSer.io_Data = (APTR) serinitstr;
  484.     serout.IOSer.io_Length = serinitlen;
  485.     serout.IOSer.io_Command = CMD_WRITE;
  486.     serout.IOSer.io_Flags = 0;
  487.     serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
  488.     DoIO(&serout);
  489. }
  490.  
  491. int
  492. asy_stop(iface)
  493. struct interface *iface;
  494. {
  495.     if (iface->dev >= ASY_MAX) {
  496.         fprintf(stderr, "asy_stop: bad dev %d\n", iface->dev);
  497.         return;
  498.     }
  499.     AbortIO(&serin);
  500.     AbortIO(&serout);
  501.     CloseDevice(&serin);
  502.     free(asy[iface->dev].input_buffer);    /* release buffer */
  503.     serialopen--;
  504. }
  505.  
  506. /* Set asynch line speed */
  507. int
  508. asy_speed(dev,speed)
  509. int dev;
  510. int speed;
  511. {
  512.     if (serialopen == 0)
  513.         return;
  514.  
  515.     AbortIO(&serin);
  516.     WaitIO(&serin);
  517.     (void) GetMsg(serinp);
  518.     asy[dev].speed = serin.io_Baud = speed;
  519.     serin.io_ReadLen = 8;
  520.     serin.io_WriteLen = 8;
  521.     serin.io_StopBits = 1;
  522.     serin.io_TermArray.TermArray0 =    serin.io_TermArray.TermArray1 = 
  523.        (ULONG)FR_END << 24 | (ULONG)FR_END << 16 | FR_END << 8 | FR_END;
  524.     serin.IOSer.io_Command = SDCMD_SETPARAMS;
  525.     serin.IOSer.io_Flags = 0;
  526.     DoIO(&serin);
  527.     if (serin.IOSer.io_Error)
  528.         printf("Bad I/O status %d on SETPARAMS\n",
  529.                     serin.IOSer.io_Error);
  530.  
  531.     serin.IOSer.io_Command = CMD_READ;
  532.     serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
  533.     serin.IOSer.io_Length = asy[dev].buflen;
  534.     asy[dev].input_len = 0;        /* clear input buffer */
  535.     serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
  536.     serin.IOSer.io_Flags = 0;    /* no quick I/O */
  537.     SendIO(&serin);
  538. }
  539.  
  540. /* Send a buffer to serial transmitter */
  541. asy_output(dev,buf,cnt)
  542. unsigned dev;
  543. char *buf;
  544. unsigned short cnt;
  545. {
  546.     /*
  547.      *  We 'know' that the transmitter is ready since we would not have
  548.      *  been called unless the previous I/O has been completed.
  549.      */
  550.     WaitIO(&serout);
  551.     GetMsg(seroutp);
  552.     serout.IOSer.io_Data = (APTR) buf;
  553.     serout.IOSer.io_Length = cnt;
  554.     serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
  555.     serout.IOSer.io_Flags = 0;    /* no quick I/O */
  556.     serout.IOSer.io_Command = CMD_WRITE;
  557.     SendIO(&serout);
  558. }
  559.  
  560. /* Read characters from the keyboard, translating them to "real" ASCII
  561.  * If none are ready, return the -1 from kbraw()
  562.  */
  563. kbread()
  564. {
  565.     char c;
  566.  
  567.     if (CheckIO(&consin)) {
  568.         WaitIO(&consin);
  569.         (void) GetMsg(consinp);
  570.         c = InputCharacter;
  571.         consin.io_Length = 1;
  572.         consin.io_Data = (APTR) &InputCharacter;
  573.         consin.io_Command = CMD_READ;
  574.         SendIO(&consin);        /* start next read up */
  575.         return (c & 0xff);
  576.     }
  577.  
  578.     return -1;        /* nuthin here */
  579. }
  580.  
  581. /* Receive characters from asynch line
  582.  * Returns count of characters read
  583.  */
  584. unsigned
  585. asy_recv(dev,buf,cnt)
  586. int dev;
  587. char *buf;
  588. unsigned cnt;
  589. {
  590.     register int actual = 0;
  591.     register long error;
  592.  
  593.     if (asy[dev].input_len == 0) {        /* if buffer is empty.. */
  594.         if (CheckIO(&serin) == NULL)    /* see if I/O has completed */
  595.             return 0;        /* nope, not yet. */
  596.         if (error = WaitIO(&serin))
  597.             printf("(SERIN) WaitIO returns %d\n", error);
  598.         if (serin.IOSer.io_Error)
  599.             printf("Bad I/O stat %d (SERIN)\n",
  600.                     serin.IOSer.io_Error);
  601.         (void) GetMsg(serinp);
  602.         /* input has completed.  fill in state variables */
  603.         asy[dev].input_len = serin.IOSer.io_Actual;
  604.         asy[dev].input_p = asy[dev].input_buffer;
  605. #ifdef    TRACE
  606.         if (trace & 0x40000000) {
  607.             int a, n, l = asy[dev].input_len;
  608.             unsigned char *b = asy[dev].input_buffer;
  609.  
  610.             a = 0;
  611.             printf("Raw serial input:\r\n");
  612.             while (l) {
  613.                 n = min(l, 16);
  614.                 fmtline(a, b, n);
  615.                 a += n;
  616.                 b += n;
  617.                 l -= n;
  618.             }
  619.             fflush(stdout);
  620.         }
  621. #endif            
  622.     }
  623.  
  624.     if (asy[dev].input_len) {    /* any chars in buffer left?  */
  625.         actual = min(asy[dev].input_len, cnt);
  626.         if (actual == 1)
  627.             *buf = *asy[dev].input_p;    /* usual case */
  628.         else
  629.             movmem(asy[dev].input_p, buf, actual);
  630.         asy[dev].input_len -= actual;
  631.         asy[dev].input_p += actual;
  632.     }
  633.  
  634.     if (asy[dev].input_len == 0) {        /* if buffer is now empty */
  635.         serin.IOSer.io_Command = CMD_READ;
  636.         serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
  637.         serin.IOSer.io_Length = asy[dev].buflen;
  638.         serin.io_SerFlags = 
  639.             SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
  640.         serin.IOSer.io_Flags = 0;    /* no quick I/O */
  641.         SendIO(&serin);
  642.     }
  643.  
  644.     return actual;
  645. }
  646.  
  647. int
  648. stxrdy(dev)
  649. {
  650.     return (CheckIO(&serout) != NULL);
  651. }
  652.  
  653. /* Create a directory listing in a temp file and return the resulting file
  654.  * descriptor. If full == 1, give a full listing; else return just a list
  655.  * of names.
  656.  *
  657.  * This function is very dependent on the workings of Aztec standard I/O;
  658.  * it uses their mechanism for generating and deleting temporary files.
  659.  */
  660. FILE *
  661. dir(path,full)
  662. char *path;
  663. int full;
  664. {
  665.     /*return (FILE *)NULL;*/
  666.     return(0L);
  667. }
  668.  
  669. #if    0
  670. bcmp(a,b,n)
  671. register char *a,*b;
  672. register int16 n;
  673. {
  674.     while(n-- != 0){
  675.         if(*a++ != *b++)
  676.             return 1;
  677.     }
  678.     return 0;
  679. }
  680. #endif
  681. SHAR_EOF
  682. cat << \SHAR_EOF > amigadev.c
  683. /*
  684.  *  Copyright (C) 1987
  685.  *  Louis A. Mamakos  WA3YMH
  686.  *  All rights reserved.
  687.  *
  688.  *  This code may not be redistributed, sold, included on any collection of
  689.  *  software which is sold.  Use of this software is restricted to inclusion
  690.  *  in the KA9Q TCP/IP software package for use on a Commodore-Amiga system.
  691.  *  Commercial use is prohibited.  Only educational and Amateur Packet Radio
  692.  *  use is allowed.
  693.  */
  694.  
  695. #ifdef    AMIGADEVDRV
  696. /*
  697.  *  This module is the meat of the Amiga 'internet.device' device driver.  There
  698.  *  are assembly language stubs in devstub.asm that call this module when user
  699.  *  program access the device driver.  Remember: the tasks running this code are
  700.  *  not our own!
  701.  */
  702.  
  703. #include <stdio.h>
  704.  
  705. /* Amiga system definitions */
  706.  
  707. #include <exec/types.h>
  708. #include <exec/nodes.h>
  709. #include <exec/lists.h>
  710. #include <exec/tasks.h>
  711. #include <exec/ports.h>
  712. #include <exec/libraries.h>
  713. #include <exec/io.h>
  714. #include <exec/devices.h>
  715. #include <exec/errors.h>
  716.  
  717.  
  718. /* get definitions of KA9Q TCP/IP protocol stuff... */
  719.  
  720. #include "machdep.h"
  721. #include "timer.h"
  722. #include "mbuf.h"
  723. #include "netuser.h"
  724. #include "internet.h"
  725. #include "icmp.h"
  726. #include "ip.h"
  727. #include "tcp.h"
  728. #include "trace.h"
  729. #include "session.h"
  730. /* device driver specific definitions */
  731. #define ListEmpty(x)    (! ((x)->lh_Head->ln_Succ))
  732.  
  733. #include "inetdev.h"
  734. #ifdef TRACE 
  735. #define tracedev(x) \
  736.     if (trace & TRACE_DEVICE) printf(x)
  737.  
  738. #define tracedev2(x,y) \
  739.     if (trace & TRACE_DEVICE) printf(x,y)
  740.  
  741. #define tracedev3(x,y,z) \
  742.     if (trace & TRACE_DEVICE) printf(x,y,z)
  743.  
  744. #define tracedev4(x,y,z,zz) \
  745.     if (trace & TRACE_DEVICE) printf(x,y,z,zz)
  746. #endif
  747. char *malloc();
  748.  
  749. extern void DSClose(), DSBeginIO(), DSAbortIO();
  750. extern struct InternetBase *DSOpen();
  751. extern long DSExpunge();
  752.  
  753. void indev_tcp_r_upcall(), indev_tcp_t_upcall(), indev_s_upcall();
  754. struct SignalSemaphore INLock;
  755. struct Library *MakeLibrary();
  756.  
  757. /* for open requests */
  758. int nopens; /* from iface */
  759. struct IOINETReq *iob = NULL;
  760. int unit_spec;
  761. struct InternetBase * dev;
  762. int OpenIt = 0, 
  763.     CN1 = 0,
  764.     IOpenedIt = 0;
  765.  
  766. extern int DeviceSignal;
  767. extern struct Process *mytask;
  768.  
  769. printlist(l)
  770. struct List *l;
  771. {
  772.   printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail, 
  773.         l->lh_TailPred);
  774. }
  775. /*
  776.  *  Initialize and install the Amiga 'internet.device'.
  777.  */
  778. void
  779. DriverInit()
  780. {
  781.     char *foo[10];
  782.     int success;
  783.     static int WeWereHere;
  784.     int x;
  785.     tracedev("DriverInit");
  786.     x = WeWereHere; 
  787.     WeWereHere = 1;
  788.     if (x)
  789.       {
  790.         printf("you tried to add the driver twice!!!\n");
  791.         return;
  792.       }
  793.     foo[0] = (char *) &DSOpen;
  794.     foo[1] = (char *) &DSClose;
  795.     foo[2] = (char *) &DSExpunge;
  796.     foo[3] = (char *) NULL;
  797.     foo[4] = (char *) &DSBeginIO;
  798.     foo[5] = (char *) &DSAbortIO;
  799.         /* add any other custom routines here */
  800.     foo[6] = (char *) -1;
  801.  
  802.     InternetBase = (struct InternetBase *)
  803.         MakeLibrary(&foo[0], (char *) NULL, (char *) NULL,
  804.             (long) sizeof(struct InternetBase), (char *) NULL);
  805.  
  806.     if (InternetBase == (struct InternetBase *) 0) {
  807.         /* display alert? */
  808.         return;
  809.     }
  810.  
  811.     InitSemaphore(&(INLock));
  812.     ObtainSemaphore(&(INLock));
  813.     InitSemaphore(&(InternetBase->ib_lock));
  814.     InternetBase->ib_lock.ss_Link.ln_Pri = 0;
  815.     InternetBase->ib_lock.ss_Link.ln_Name = "internet.device lock";
  816.  
  817.     NewList(&InternetBase->ib_Units);
  818.     InternetBase->ib_Units.lh_Type = NT_UNKNOWN;
  819.  
  820.     InternetBase->lib.lib_Node.ln_Type = NT_DEVICE;
  821.     InternetBase->lib.lib_Node.ln_Pri = 0;
  822.     InternetBase->lib.lib_Node.ln_Name = "internet.device";
  823.     InternetBase->lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
  824.     InternetBase->lib.lib_Version = IN_VERSION;
  825.     InternetBase->lib.lib_Revision = IN_REVISION;
  826.     InternetBase->lib.lib_IdString =
  827.              (APTR) "internet.device   23 May 1987\r\n";
  828.  
  829.     success = AddDevice(InternetBase);
  830.     Savea4();
  831.     OpenIt = 0;
  832.     IOpenedIt = 0;
  833.     nopens = 1;
  834.     CN1 = 5;
  835.     if (success != 0)
  836.           myoserr("driver open");
  837.     printf("driver added returned %d\n",success);
  838.  
  839. }
  840.  
  841. void
  842. DriverShutdown()
  843. {
  844.     long error;
  845.     extern long *RemoveDevice();
  846.  
  847.     if (!InternetBase)
  848.         return;
  849.  
  850.     if (error = RemDevice(InternetBase))
  851.         printf("Can't remove device: error %ld\n", error);
  852.  
  853. }
  854.  
  855. struct InternetBase *
  856. NetDevOpen(mdev, munit_spec, miob, mflags)
  857.     struct InternetBase *mdev;
  858.     struct IOINETReq *miob;
  859.     ULONG munit_spec, mflags;
  860. {
  861.  
  862.     iob = miob;
  863.     dev = mdev;
  864.     unit_spec = munit_spec;
  865.  
  866.     if (IOpenedIt == 1)
  867.       {
  868.         CN1++;
  869.         return NULL;
  870.       }
  871.     OpenIt = 1;
  872.     Permit();
  873.     while (IOpenedIt == 0);
  874.     Forbid();
  875.     IOpenedIt = 0;
  876.     return dev;
  877. }
  878. check_driver()
  879. {
  880.     register struct INET_Unit *unit;
  881.     register struct tcb *tcb;
  882.     if (OpenIt != 0)
  883.         {
  884.  
  885.     printf("open request!\n");
  886.     
  887.     switch (unit_spec) {
  888.         case INET_UNIT_TCP:
  889.         case INET_UNIT_UDP:
  890.             break;
  891.         default:
  892.             iob->io_Error = IOERR_OPENFAIL;
  893.             iob->io_Device = NULL;
  894.             iob->io_Unit = NULL;
  895.             OpenIt = 0;
  896.             IOpenedIt = 1;
  897.             goto doneopen;
  898.     }
  899.  
  900.     if ((unit = (struct INET_Unit *)
  901.             malloc(sizeof(struct INET_Unit))) == NULL) {
  902.         iob->io_Error = IOERR_OPENFAIL;
  903.         OpenIt = 0;
  904.         IOpenedIt = 1;
  905.         goto doneopen;
  906.     }
  907.     tracedev2("malloc ok %x\n", unit);
  908.     iob->io_Unit = unit;
  909.     iob->io_Device = (struct Device *)dev;
  910.     dev->lib.lib_OpenCnt++;
  911.  
  912.     unit->iu_Unit.ln_Type = NT_UNKNOWN;
  913.     unit->iu_Unit.ln_Pri = 0;
  914.  
  915.     NewList(&unit->iu_Input);
  916.     NewList(&unit->iu_Output);
  917. printf("newlist ok\n");
  918.     unit->iu_Input.lh_Type = NT_UNKNOWN;    /* gee, what do we really */
  919.     unit->iu_Output.lh_Type = NT_UNKNOWN;    /* call these... */
  920.     unit->iu_user = iob->io_Offset;        /* always returned in Offset */
  921.     unit->iu_Act_Input = NULL;
  922.     unit->iu_Act_Output = NULL;
  923.     iob->io_lsocket.address = ip_addr;
  924.     iob->io_lsocket.port = lport++;    
  925.     AddTail(&InternetBase->ib_Units, &unit->iu_Unit);
  926.     /* perform protocol specific open functions */
  927.     printf("addtail\n");
  928.  
  929.     switch (unit_spec) {
  930.     case INET_UNIT_TCP:
  931. /*        Forbid(); */
  932.         tcb = open_tcp(&(iob->io_lsocket), &(iob->io_fsocket),
  933.             (USHORT) iob->io_Offset, (USHORT) iob->io_TCP_Window,
  934.             indev_tcp_r_upcall, indev_tcp_t_upcall, indev_s_upcall,
  935.             iob->io_INET_TOS, (char *)unit);
  936.  
  937. /*        Permit();*/
  938.         if (tcb == NULL)
  939.             goto fail;
  940.         unit->iu_Unit.ln_Name = "TCP Connection";
  941.         unit->iu_type = INET_UNIT_TCP;
  942.         unit->iu_ccb = tcb;
  943. printf("cpopen is %d\n", tcb);
  944.         break;
  945.  
  946.     default:
  947.        fail:
  948.         iob->io_Error = IOERR_OPENFAIL;
  949.         dev->lib.lib_OpenCnt--;
  950.         Remove(unit);
  951.         free(unit);
  952.         OpenIt = 0;
  953.         IOpenedIt = 1;
  954.         goto doneopen;
  955.     }
  956.         tracedev2("dev is %d\n", dev);
  957.     OpenIt = 0;
  958.     IOpenedIt = 1;
  959.   }
  960. doneopen:
  961.   /* spin until that other guy is all done. We will not get through
  962.    * this spin until the other guy has done a Forbid() and
  963.    * then a Permit(), since the IopenedIt gets cleared 
  964.    * AFTER the Forbid(). Sorry i do not use semaphores but
  965.    * i do not have 1.2 autodocs so am not totally up on their
  966.    * use.
  967.    */
  968.   while (IOpenedIt);
  969. }
  970. CheckTcp()
  971. {
  972.   struct Node *head = InternetBase->ib_Units.lh_Head;
  973.  
  974.   struct INET_Unit *unit = (struct INET_Unit *) head;
  975.   struct tcb *tcb;
  976.   /* let the other guys in */
  977.   ReleaseSemaphore(&(INLock));
  978.   eihalt();
  979.   ObtainSemaphore(&(INLock));
  980.   tracedev("start checktcp\n");
  981.   tracedev4("heda %x Pred is %x Succ is %x\n", head,head->ln_Pred, head->ln_Succ);
  982.   for (;unit->iu_Unit.ln_Succ;unit = unit->iu_Unit.ln_Succ)
  983.     {
  984.       tracedev3("checktcp: %x Succ %d\n", unit, unit->iu_Unit.ln_Succ);
  985.       if (unit->iu_type != INET_UNIT_TCP)
  986.         {
  987.           tracedev("not a tcp\n");
  988.           continue;
  989.         }      
  990.       tcb = (struct tcb *) unit->iu_ccb;
  991.       if (tcb == NULL)
  992.         {
  993.           tracedev("NULL tcb in unit\n");  
  994.           continue;
  995.         }
  996.       if (tcb->state == ESTABLISHED)
  997.         {
  998.           tracedev("unit state is established!\n");
  999. /*          continue;*/
  1000.         }
  1001.      tracedev("do the upcall\n");
  1002.      do_tupcall(tcb, 512); /* for now- it wil do the right thing */
  1003.      if (tcb->rcvcnt > 0)
  1004.        do_rupcall(tcb, tcb->rcvcnt);
  1005.   }
  1006.   tracedev("done checktcp\n");
  1007. /*  ReleaseSemaphore(&(INLock));*/
  1008. }
  1009. void DevClose(dev, iob)
  1010.     struct InternetBase *dev;
  1011.     struct IOINETReq *iob;
  1012. {
  1013.     register struct INET_Unit *unit;
  1014.         struct tcb *tcb;
  1015.  
  1016.         unit = iob->io_Unit;
  1017.         tcb = unit->iu_ccb;
  1018.     del_tcp(tcb);
  1019.     Remove(unit);
  1020.     free(unit);
  1021.     iob->io_Unit = NULL;
  1022.  
  1023.     iob->io_Device = (struct Device *)dev;
  1024.     dev->lib.lib_OpenCnt--;
  1025.  
  1026.     /* remove iu_Unit from ib_Units list */
  1027.     /* decrement library use count */
  1028.     /* free unit structure */
  1029.     /* delete TCP/UDP connection del_tcp()/del_udp() */
  1030. }
  1031.  
  1032. long DevExpunge(dev)
  1033.     struct InternetBase *dev;
  1034. {
  1035.     register char *m;
  1036.     register long len;
  1037.  
  1038.  
  1039.     if (InternetBase->lib.lib_OpenCnt) {
  1040.         InternetBase->lib.lib_Flags |= LIBF_DELEXP;
  1041.         return 0;
  1042.     }
  1043.     Remove(InternetBase);    /* remove from library list */
  1044.     len = InternetBase->lib.lib_NegSize + InternetBase->lib.lib_PosSize;
  1045.     m = (char *) ((ULONG)InternetBase - InternetBase->lib.lib_NegSize);
  1046.     FreeMem(m, len);
  1047.     return 0;
  1048. }
  1049.  
  1050. #define    C_IMMED        (1<<0)
  1051. #define    C_READ        (1<<1)
  1052. #define    C_WRITE        (1<<2)
  1053. void cmd_Invalid(), cmd_Reset(), cmd_Read(), cmd_Write(), cmd_Update(),
  1054.     cmd_Clear(), cmd_Stop(), cmd_Start(), cmd_Flush(), PerformIO();
  1055.  
  1056. struct Commands {
  1057.     void    (*cmd_func)();
  1058.     int    cmd_flags;
  1059. } commands [] = {
  1060.     { cmd_Invalid,     C_IMMED        },    /* invalid    */
  1061.     { cmd_Reset,    C_IMMED        },    /* CMD_RESET    */
  1062.     { cmd_Read,    C_READ        },    /* CMD_READ    */
  1063.     { cmd_Write,    C_WRITE        },    /* CMD_WRITE    */
  1064.     { cmd_Update,    C_WRITE     },    /* CMD_UPDATE    */
  1065.     { cmd_Clear,    C_IMMED        },    /* CMD_CLEAR    */
  1066.     { cmd_Stop,    C_IMMED        },    /* CMD_STOP    */
  1067.     { cmd_Start,    C_IMMED        },    /* CMD_START    */
  1068.     { cmd_Flush,    C_IMMED        },    /* CMD_FLUSH    */
  1069. };
  1070.  
  1071. /*  define last valid command */
  1072. #define    MAX_IO_COMMAND    CMD_FLUSH
  1073.  
  1074.  
  1075. /* BeginIO is called to begin processing of the I/O request */
  1076.  
  1077. void DevBeginIO(iob, dev)
  1078.     struct IOINETReq *iob;
  1079.     struct InternetBase *dev;
  1080. {
  1081.     register struct Commands *cmd;
  1082.     register struct INET_Unit *unit = iob->io_Unit;
  1083.     ObtainSemaphore(&(INLock));
  1084.     if (iob->io_Command > MAX_IO_COMMAND) {
  1085.         cmd_Invalid(iob, iob->io_Unit);
  1086.         goto done;
  1087.     }
  1088.     tracedev("io. ObtainSme\n");
  1089.  
  1090.     tracedev("got it\n");
  1091.     cmd = &commands[iob->io_Command];
  1092.     tracedev2("cmd is %d\n",iob->io_Command);
  1093.     tracedev2("flags %d\n", iob->io_Flags);
  1094.     if ((cmd->cmd_flags & C_IMMED) == 0) {
  1095.  
  1096.         /*
  1097.          *  Code for commands which can queue
  1098.          */
  1099.  
  1100.         if ((cmd->cmd_flags & C_READ)/* && (unit->iu_Act_Input)*/) {
  1101.             AddTail(&unit->iu_Input, iob);
  1102.             iob->io_Flags &= ~IOF_QUICK;
  1103.             iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  1104.             tracedev3("added %d to read queue of unit %d\n", iob, unit);
  1105.             goto done;
  1106.         }
  1107.  
  1108.         if ((cmd->cmd_flags & C_WRITE)/* && (unit->iu_Act_Output)*/) {
  1109.             AddTail(&unit->iu_Output, iob);
  1110.             iob->io_Flags &= ~IOF_QUICK;
  1111.             iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  1112.             tracedev3("added %d to write queue of unit %d\n", iob, unit);
  1113.             goto done;
  1114.         }
  1115.     }
  1116.     PerformIO(iob, unit);
  1117. done:     tracedev4("flags QUI %x ~QUI %x  %d\n", IOF_QUICK, ~IOF_QUICK,
  1118.             iob->io_Flags);
  1119.   Signal(mytask, DeviceSignal);
  1120.   ReleaseSemaphore(&(INLock));
  1121. }
  1122.  
  1123. void DevAbortIO(iob, dev)
  1124.     struct IOINETReq *iob;
  1125.     struct InternetBase *dev;
  1126. {
  1127.     printf("DevAbortIo\n");
  1128. }
  1129.  
  1130. void
  1131. PerformIO(iob, unit)
  1132.     struct IOINETReq *iob;
  1133.     struct INET_Unit *unit;
  1134. {
  1135.     iob->io_Error = 0;
  1136.     iob->io_Actual = 0;
  1137.     (*commands[iob->io_Command].cmd_func)(iob, unit);
  1138. }
  1139.  
  1140. void
  1141. TermIO(iob, unit)
  1142.     struct IOINETReq *iob;
  1143.     struct INET_Unit *unit;
  1144. {
  1145.     struct tcb *tcb;
  1146.         tcb = (struct tcb *) unit->iu_ccb;
  1147.     iob->io_OldState = iob->io_State;
  1148.     iob->io_State = tcb->state;
  1149.     if ((iob->io_Flags & IOF_QUICK) == 0)
  1150.         /* not quick I/O */
  1151.         ReplyMsg(&iob->io_Message);
  1152. }
  1153.  
  1154. void
  1155. cmd_Invalid(iob, unit)
  1156.     struct IOINETReq *iob;
  1157.     struct INET_Unit *unit;
  1158. {
  1159.     iob->io_Error = IOERR_NOCMD;
  1160.     TermIO(iob, unit);
  1161. }
  1162.  
  1163. void
  1164. cmd_Reset(iob, unit)
  1165.     struct IOINETReq *iob;
  1166.     struct INET_Unit *unit;
  1167. {
  1168.     iob->io_Error = IOERR_NOCMD;
  1169.     TermIO(iob, unit);
  1170. }
  1171.  
  1172. void
  1173. cmd_Read(iob, unit)
  1174.     struct IOINETReq *iob;
  1175.     struct INET_Unit *unit;
  1176. {
  1177.     iob->io_Error = IOERR_NOCMD;
  1178.     TermIO(iob, unit);
  1179. }
  1180.  
  1181. void
  1182. cmd_Write(iob, unit)
  1183.     struct IOINETReq *iob;
  1184.     struct INET_Unit *unit;
  1185. {
  1186.     iob->io_Error = IOERR_NOCMD;
  1187.     TermIO(iob, unit);
  1188. }
  1189.  
  1190. void
  1191. cmd_Update(iob, unit)
  1192.     struct IOINETReq *iob;
  1193.     struct INET_Unit *unit;
  1194. {
  1195.     iob->io_Error = IOERR_NOCMD;
  1196.     TermIO(iob, unit);
  1197. }
  1198.  
  1199. void
  1200. cmd_Clear(iob, unit)
  1201.     struct IOINETReq *iob;
  1202.     struct INET_Unit *unit;
  1203. {
  1204.     iob->io_Error = IOERR_NOCMD;
  1205.     TermIO(iob, unit);
  1206. }
  1207.  
  1208.  
  1209. void
  1210. cmd_Stop(iob, unit)
  1211.     struct IOINETReq *iob;
  1212.     struct INET_Unit *unit;
  1213. {
  1214.     iob->io_Error = IOERR_NOCMD;
  1215.     TermIO(iob, unit);
  1216. }
  1217.  
  1218.  
  1219. void
  1220. cmd_Start(iob, unit)
  1221.     struct IOINETReq *iob;
  1222.     struct INET_Unit *unit;
  1223. {
  1224.     iob->io_Error = IOERR_NOCMD;
  1225.     TermIO(iob, unit);
  1226. }
  1227.  
  1228.  
  1229. void
  1230. cmd_Flush(iob, unit)
  1231.     struct IOINETReq *iob;
  1232.     struct INET_Unit *unit;
  1233. {
  1234.     iob->io_Error = IOERR_NOCMD;
  1235.     TermIO(iob, unit);
  1236. }
  1237.  
  1238.  
  1239. /* TCP receiver upcall routine.  Called with TCB pointer and number of bytes
  1240.    available */
  1241.  
  1242.  
  1243. do_rupcall(tcb, cnt)
  1244.     struct tcb *tcb;
  1245.     int16 cnt;
  1246. {
  1247.     struct mbuf *bp;
  1248.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  1249.     int amount, recamount;
  1250.     struct IOINETReq *iob;
  1251. /*    ObtainSemaphore(&(INLock));*/
  1252.     if (ListEmpty(&(unit->iu_Input)))
  1253.       goto done;
  1254.     iob = unit->iu_Act_Input = unit->iu_Input.lh_Head;
  1255.     tracedev4("dev rupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
  1256.     if (iob != NULL)
  1257.       {
  1258.         Remove(iob);
  1259.             amount = min(cnt, iob->io_Length);
  1260.         tracedev3("call recv_tcp %d bytes avail %d\n", amount, cnt);
  1261.         recamount = recv_tcp(tcb, &bp, amount);
  1262.         iob->io_Actual = dqdata(bp, iob->io_Data, recamount);
  1263.         tracedev2("recv_tcp after got %d bytes\n", iob->io_Actual);
  1264.         TermIO(iob, unit);
  1265. /*        ReplyMsg(&(iob->io_Message));*/
  1266.       }
  1267. done:    
  1268. /*  ReleaseSemaphore(&(INLock));        */
  1269. }
  1270. /* TCP receiver upcall routine.  Called with TCB pointer and number of bytes
  1271.    available */
  1272.  
  1273. void
  1274. indev_tcp_r_upcall(tcb, cnt)
  1275.     struct tcb *tcb;
  1276.     int16 cnt;
  1277. {
  1278. /*    ObtainSemaphore(&(INLock));*/
  1279.     do_rupcall(tcb, 512);
  1280. /*  ReleaseSemaphore(&(INLock));        */
  1281. }
  1282.  
  1283. /* TCP transmitter upcall routine.  Called with TCB pointer and number of bytes
  1284.    free in send window */
  1285.  
  1286.  
  1287. do_tupcall(tcb, avail)
  1288.     struct tcb *tcb;
  1289.     int16 avail;
  1290. {
  1291.     struct mbuf *bp, *qdata();
  1292.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  1293.     int amount;
  1294.     struct IOINETReq *iob;
  1295.  
  1296.     if (ListEmpty(&(unit->iu_Output)))
  1297.       goto done;
  1298.     tracedev("non-empty Output\n");
  1299.     iob = unit->iu_Act_Output = unit->iu_Output.lh_Head;
  1300.     tracedev4("dev tupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
  1301.     if (iob != NULL)
  1302.       {
  1303.         Remove(iob);
  1304.  
  1305.             amount = min(avail, iob->io_Length);
  1306.         tracedev3("t_upcall- send_tcp for addr %x %d bytes\n",iob->io_Data,
  1307.             amount);
  1308.         bp = qdata(iob->io_Data, amount);
  1309.         iob->io_Actual = send_tcp(tcb, bp);
  1310.         tracedev2("send_tcp after got %d bytes\n", iob->io_Actual);
  1311.         TermIO(iob, unit);
  1312. /*        ReplyMsg(&(iob->io_Message));*/
  1313.         unit->iu_Act_Output = NULL;
  1314.       }
  1315. done:
  1316.  
  1317.  
  1318. }
  1319. void
  1320. indev_tcp_t_upcall(tcb, avail)
  1321.     struct tcb *tcb;
  1322.     int16 avail;
  1323. {
  1324. /*    ObtainSemaphore(&(INLock));*/
  1325.     do_tupcall(tcb, avail);
  1326. /*  ReleaseSemaphore(&(INLock));        */
  1327.  
  1328. }
  1329.  
  1330. void
  1331. indev_s_upcall(tcb, old, new)
  1332.     struct tcb *tcb;
  1333.     char old, new;
  1334. {
  1335.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  1336.     char notify = 0;
  1337.     extern char *tcpstates[];
  1338.     extern char *reasons[];
  1339.     extern char *unreach[];
  1340.     extern char *exceed[];
  1341.  
  1342.     /* Can't add a check for unknown connection here, it would loop
  1343.      * on a close upcall! We're just careful later on.
  1344.      */
  1345.  
  1346.     if(unit != NULL)
  1347.         notify = 1;
  1348.  
  1349.     switch(new){
  1350.     case CLOSE_WAIT:
  1351.         if(notify)
  1352.             printf("%s\r\n",tcpstates[new]);
  1353.         close_tcp(tcb);
  1354.         break;
  1355.     case CLOSED:    /* court adjourned */
  1356.         if(notify){
  1357.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  1358.             if(tcb->reason == NETWORK){
  1359.                 switch(tcb->type){
  1360.                 case DEST_UNREACH:
  1361.                     printf(": %s unreachable",unreach[tcb->code]);
  1362.                     break;
  1363.                 case TIME_EXCEED:
  1364.                     printf(": %s time exceeded",exceed[tcb->code]);
  1365.                     break;
  1366.                 }
  1367.             }
  1368.             printf(")\r\n");
  1369.         }
  1370.         del_tcp(tcb);
  1371.         break;
  1372.     default:
  1373.         if(notify)
  1374.             printf("%s\r\n",tcpstates[new]);
  1375.         break;
  1376.     }
  1377.     fflush(stdout);
  1378.  
  1379. }
  1380. #endif
  1381. SHAR_EOF
  1382. cat << \SHAR_EOF > iproute.c
  1383. /* Lower half of IP, consisting of gateway routines
  1384.  * Includes routing and options processing code
  1385.  */
  1386. #include <stdio.h>
  1387. #include "machdep.h"
  1388. #include "mbuf.h"
  1389. #include "internet.h"
  1390. #include "timer.h"
  1391. #include "netuser.h"
  1392. #include "ip.h"
  1393. #include "icmp.h"
  1394. #include "iface.h"
  1395. #ifdef    TRACE
  1396. #include "trace.h"
  1397. #endif
  1398.  
  1399. struct route *routes[32][NROUTE];    /* Routing table */
  1400. struct route r_default;            /* Default route entry */
  1401.  
  1402. int32 ip_addr;
  1403. struct ip_stats ip_stats;
  1404.  
  1405. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  1406.  * coming or going, must pass.
  1407.  *
  1408.  * This router is a temporary hack, since it only does host-specific or
  1409.  * default routing (no hierarchical routing yet).
  1410.  *
  1411.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  1412.  * broadcast. The router will kick the packet upstairs regardless of the
  1413.  * IP destination address.
  1414.  */
  1415. void
  1416. ip_route(bp,rxbroadcast)
  1417. struct mbuf *bp;
  1418. char rxbroadcast;    /* True if packet had link broadcast address */
  1419. {
  1420.     register struct ip_header *ip;    /* IP header being processed */
  1421.     int16 ip_len;            /* IP header length */
  1422.     int16 buflen;            /* Length of mbuf */
  1423.     int16 length;            /* Total datagram length */
  1424.     int32 target;            /* Target IP address */
  1425.     int32 gateway;            /* Gateway IP address */
  1426.     register struct route *rp;    /* Route table entry */
  1427.     struct route *rt_lookup();
  1428.     int opi;            /* Index into options field */
  1429.     int opt_len;            /* Length of current option */
  1430.     int strict;            /* Strict source routing flag */
  1431.     struct mbuf *sbp;        /* IP header for fragmenting */
  1432.     int16 fl_offs;            /* fl_offs field of datagram */
  1433.     int16 offset;            /* Offset of fragment */
  1434.     char precedence;        /* Extracted from tos field */
  1435.     char delay;
  1436.     char throughput;
  1437.     char reliability;
  1438.  
  1439.     ip_stats.total++;
  1440.     buflen = len_mbuf(bp);
  1441.     if(buflen < sizeof(struct ip_header)){
  1442.         /* The packet is shorter than a legal IP header */
  1443.         ip_stats.runt++;
  1444.         free_p(bp);
  1445.         return;
  1446.     }
  1447.     ip = (struct ip_header *)bp->data;
  1448.     length = ntohs(ip->length);
  1449.     if(buflen > length){
  1450.         /* Packet has excess garbage (e.g., Ethernet padding); trim */
  1451.         if(bp->next == NULLBUF){
  1452.             /* One mbuf, just adjust count */
  1453.             bp->cnt = length;
  1454.         } else {
  1455.             struct mbuf *nbp;
  1456.             /* Copy to a new one */
  1457.             nbp = copy_p(bp,length);
  1458.             free((char *)bp);
  1459.             bp = nbp;
  1460.             ip = (struct ip_header *)bp->data;
  1461.         }
  1462.     }
  1463.     ip_len = lonibble(ip->v_ihl) * sizeof(int32);
  1464.     if(ip_len < sizeof(struct ip_header)){
  1465.         /* The IP header length field is too small */
  1466.         ip_stats.length++;
  1467.         free_p(bp);
  1468.         return;
  1469.     }
  1470.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  1471.         /* Bad IP header checksum; discard */
  1472.         ip_stats.checksum++;
  1473.         free_p(bp);
  1474.         return;
  1475.     }
  1476.     if(hinibble(ip->v_ihl) != IPVERSION){
  1477.         /* We can't handle this version of IP */
  1478.         ip_stats.version++;
  1479.         free_p(bp);
  1480.         return;
  1481.     }
  1482.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  1483.     if(ntohl(ip->dest) == ip_addr || rxbroadcast){
  1484. #ifdef    GWONLY
  1485.     /* We're only a gateway, we have no host level protocols */
  1486.         if(!rxbroadcast)
  1487.             icmp_output(bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  1488.         free_p(bp);
  1489. #else
  1490. #ifdef    TRACE
  1491.         if(trace & TRACE_SELF && ntohl(ip->source) == ip_addr){
  1492.             printf("loopback:\r\n");
  1493.             if((trace & TRACE_HDR) > 2)
  1494.                 ip_dump(bp);
  1495.             if(trace & TRACE_DUMP)
  1496.                 hexdump(bp);
  1497.             fflush(stdout);
  1498.         }
  1499. #endif
  1500.         ip_recv(bp,rxbroadcast);
  1501. #endif
  1502.         return;
  1503.     }
  1504.     /* If we get here, we must forward the packet.
  1505.      * Process options, if any. Also compute length of secondary IP
  1506.      * header in case fragmentation is needed later
  1507.      */
  1508.     strict = 0;
  1509.     for(opi = sizeof(struct ip_header);opi < ip_len; opi += opt_len){
  1510.         char *opt;    /* Points to current option */
  1511.         int opt_type;    /* Type of current option */
  1512.         int pointer;    /* Pointer field of current option */
  1513.         int32 *addr;    /* Pointer to an IP address field in option */
  1514.  
  1515.         opt = (char *)ip + opi;
  1516.         opt_type = opt[0] & OPT_NUMBER;
  1517.  
  1518.         /* Handle special 1-byte do-nothing options */
  1519.         if(opt_type == IP_EOL)
  1520.             break;        /* End of options list, we're done */
  1521.         if(opt_type == IP_NOOP){
  1522.             opt_len = 1;    /* No operation, skip to next option */
  1523.             continue;
  1524.         }
  1525.         /* Other options have a length field */
  1526.         opt_len = opt[1] & 0xff;
  1527.  
  1528.         /* Process options */
  1529.         switch(opt_type){
  1530.         case IP_SSROUTE:/* Strict source route & record route */
  1531.             strict = 1;
  1532.         case IP_LSROUTE:/* Loose source route & record route */
  1533.             /* Source routes are ignored unless the datagram appears to
  1534.              * be for us
  1535.              */
  1536.             if(ntohl(ip->dest) != ip_addr)
  1537.                 continue;
  1538.         case IP_RROUTE:    /* Record route */
  1539.             pointer = (opt[2] & 0xff) - 1;
  1540.             if(pointer + sizeof(int32) <= opt_len){
  1541.                 /* Insert our address in the list */
  1542.                 addr = (int32 *)&opt[pointer];
  1543.                 if(opt_type != IP_RROUTE)
  1544.                     /* Old value is next dest only for source routing */
  1545.                     ip->dest = *addr;
  1546.                 *addr = htonl(ip_addr);
  1547.                 opt[2] += 4;
  1548.             } else {
  1549.                 /* Out of space; return a parameter problem and drop */
  1550.                 union icmp_args icmp_args;
  1551.  
  1552.                 icmp_args.unused = 0;
  1553.                 icmp_args.pointer = sizeof(struct ip_header) + opi;
  1554.                 icmp_output(bp,PARAM_PROB,0,&icmp_args);
  1555.                 free_p(bp);
  1556.                 return;
  1557.             }
  1558.             break;
  1559.         }
  1560.     }
  1561.     /* Decrement TTL and discard if zero */
  1562.     if(--ip->ttl == 0){
  1563.         /* Send ICMP "Time Exceeded" message */
  1564.         icmp_output(bp,TIME_EXCEED,0,NULLICMP);
  1565.         free_p(bp);
  1566.         return;
  1567.     }
  1568.     /* Note this address may have been modified by source routing */
  1569.     target = ntohl(ip->dest);
  1570.  
  1571.     /* Look up target address in routing table */
  1572.     if((rp = rt_lookup(target)) == NULLROUTE){
  1573.         /* No route exists, return unreachable message */
  1574.         icmp_output(bp,DEST_UNREACH,HOST_UNREACH,NULLICMP);
  1575.         free_p(bp);
  1576.         return;
  1577.     }
  1578.     /* Find gateway; zero gateway in routing table means "send direct" */
  1579.     if(rp->gateway == (int32)0)
  1580.         gateway = target;
  1581.     else
  1582.         gateway = rp->gateway;
  1583.  
  1584.     if(strict && gateway != target){
  1585.         /* Strict source routing requires a direct entry */
  1586.         icmp_output(bp,DEST_UNREACH,ROUTE_FAIL,NULLICMP);
  1587.         free_p(bp);
  1588.         return;
  1589.     }
  1590.     precedence = PREC(ip->tos);
  1591.     delay = ip->tos & DELAY;
  1592.     throughput = ip->tos & THRUPUT;
  1593.     reliability = ip->tos & RELIABILITY;
  1594.  
  1595.     if(length <= rp->interface->mtu){
  1596.         /* Datagram smaller than interface MTU; send normally */
  1597.         /* Recompute header checksum */
  1598.         ip->checksum = 0;
  1599.         ip->checksum = cksum(NULLHEADER,bp,ip_len);
  1600.         (*rp->interface->send)(bp,rp->interface,gateway,
  1601.             precedence,delay,throughput,reliability);
  1602.         return;
  1603.     }
  1604.     /* Fragmentation needed */
  1605.     fl_offs = ntohs(ip->fl_offs);
  1606.     if(fl_offs & DF){
  1607.         /* Don't Fragment set; return ICMP message and drop */
  1608.         icmp_output(bp,DEST_UNREACH,FRAG_NEEDED,NULLICMP);
  1609.         free_p(bp);
  1610.         return;
  1611.     }
  1612.     /* Create copy of IP header for each fragment */
  1613.     sbp = copy_p(bp,ip_len);
  1614.     pullup(&bp,NULLCHAR,ip_len);
  1615.     length -= ip_len;
  1616.  
  1617.     /* Create fragments */
  1618.     offset = (fl_offs & F_OFFSET) << 3;
  1619.     while(length != 0){
  1620.         int16 fragsize;        /* Size of this fragment's data */
  1621.         struct mbuf *f_header;    /* Header portion of fragment */
  1622.         struct ip_header *fip;    /* IP header */
  1623.         struct mbuf *f_data;    /* Data portion of fragment */
  1624.  
  1625.         f_header = copy_p(sbp,ip_len);
  1626.         fip = (struct ip_header *)f_header->data;
  1627.         fip->fl_offs = htons(offset >> 3);
  1628.         if(length + ip_len <= rp->interface->mtu){
  1629.             /* Last fragment; send all that remains */
  1630.             fragsize = length;
  1631.         } else {
  1632.             /* More to come, so send multiple of 8 bytes */
  1633.             fragsize = (rp->interface->mtu - ip_len) & 0xfff8;
  1634.             fip->fl_offs |= htons(MF);
  1635.         }
  1636.         fip->length = htons(fragsize + ip_len);
  1637.         /* Recompute header checksum */
  1638.         fip->checksum = 0;
  1639.         fip->checksum = cksum(NULLHEADER,f_header,ip_len);
  1640.  
  1641.         /* Extract portion of data and link in */
  1642.         f_data = copy_p(bp,fragsize);
  1643.         pullup(&bp,NULLCHAR,fragsize);
  1644.         f_header->next = f_data;
  1645.  
  1646.         (*rp->interface->send)(f_header,rp->interface,gateway,
  1647.             precedence,delay,throughput,reliability);
  1648.         offset += fragsize;
  1649.         length -= fragsize;
  1650.     }
  1651.     free_p(sbp);
  1652. }
  1653.  
  1654. /* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
  1655. int
  1656. rt_add(target,bits,gateway,metric,interface)
  1657. int32 target;    /* Target IP address prefix */
  1658. unsigned bits;    /* Size of target address prefix in bits (0-32) */
  1659. int32 gateway;
  1660. int metric;
  1661. struct interface *interface;
  1662. {
  1663.     struct route *rp,**hp,*rt_lookup();
  1664.     int16 hash_ip(),i;
  1665.     char *malloc();
  1666.  
  1667.     if(interface == NULLIF)
  1668.         return -1;
  1669.  
  1670.     /* Zero bits refers to the default route */
  1671.     if(bits == 0){
  1672.         rp = &r_default;
  1673.     } else {
  1674.         if(bits > 32)
  1675.             bits = 32;
  1676.  
  1677.         /* Mask off don't-care bits */
  1678.         for(i=31;i >= bits;i--)
  1679.             target &= ~(0x80000000 >> i);
  1680.  
  1681.         /* Search appropriate chain for existing entry */
  1682.         for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  1683.             if(rp->target == target)
  1684.                 break;
  1685.         }
  1686.     }
  1687.     if(rp == NULLROUTE){
  1688.         /* The target is not already in the table, so create a new
  1689.          * entry and put it in.
  1690.          */
  1691.         if((rp = (struct route *)malloc(sizeof(struct route))) == NULLROUTE)
  1692.             return -1;    /* No space */
  1693.         /* Insert at head of table */
  1694.         rp->prev = NULLROUTE;
  1695.         hp = &routes[bits-1][hash_ip(target)];
  1696.         rp->next = *hp;
  1697.         if(rp->next != NULLROUTE)
  1698.             rp->next->prev = rp;
  1699.         *hp = rp;
  1700.     }
  1701.     rp->target = target;
  1702.     rp->gateway = gateway;
  1703.     rp->metric = metric;
  1704.     rp->interface = interface;
  1705.     return 0;
  1706. }
  1707.  
  1708. /* Remove an entry from the IP routing table. Returns 0 on success, -1
  1709.  * if entry was not in table.
  1710.  */
  1711. int
  1712. rt_drop(target,bits)
  1713. int32 target;
  1714. unsigned bits;
  1715. {
  1716.     register struct route *rp;
  1717.     struct route *rt_lookup();
  1718.     unsigned i;
  1719.  
  1720.     if(bits == 0){
  1721.         /* Nail the default entry */
  1722.         r_default.interface = NULLIF;
  1723.         return 0;
  1724.     }
  1725.     if(bits > 32)
  1726.         bits = 32;
  1727.  
  1728.     /* Mask off don't-care bits */
  1729.     for(i=31;i > bits;i--)
  1730.         target &= ~(0x80000000 >> i);
  1731.  
  1732.     /* Search appropriate chain for existing entry */
  1733.     for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  1734.         if(rp->target == target)
  1735.             break;
  1736.     }
  1737.     if(rp == NULLROUTE)
  1738.         return -1;    /* Not in table */
  1739.  
  1740.     if(rp->next != NULLROUTE)
  1741.         rp->next->prev = rp->prev;
  1742.     if(rp->prev != NULLROUTE)
  1743.         rp->prev->next = rp->next;
  1744.     else
  1745.         routes[bits-1][hash_ip(target)] = rp->next;
  1746.  
  1747.     free((char *)rp);
  1748.     return 0;
  1749. }
  1750.  
  1751. /* Compute hash function on IP address */
  1752. static int16
  1753. hash_ip(addr)
  1754. register int32 addr;
  1755. {
  1756.     register int16 ret;
  1757.  
  1758.     ret = hiword(addr);
  1759.     ret ^= loword(addr);
  1760.     ret %= NROUTE;
  1761.     return ret;
  1762. }
  1763. #ifndef    GWONLY
  1764. /* Given an IP address, return the MTU of the local interface used to
  1765.  * reach that destination. This is used by TCP to avoid local fragmentation
  1766.  */
  1767. int16
  1768. ip_mtu(addr)
  1769. int32 addr;
  1770. {
  1771.     register struct route *rp;
  1772.     struct route *rt_lookup();
  1773.  
  1774.     rp = rt_lookup(addr);
  1775.     if(rp != NULLROUTE && rp->interface != NULLIF)
  1776.         return rp->interface->mtu;
  1777.     else
  1778.         return 0;
  1779. }
  1780. #endif
  1781. /* Look up target in hash table, matching the entry having the largest number
  1782.  * of leading bits in common. Return default route if not found;
  1783.  * if default route not set, return NULLROUTE
  1784.  */
  1785. static struct route *
  1786. rt_lookup(target)
  1787. int32 target;
  1788. {
  1789.     register struct route *rp;
  1790.     int16 hash_ip();
  1791.     unsigned bits;
  1792.  
  1793.     for(bits = 32;bits != 0; bits--){
  1794.         if(bits != 32)
  1795.             target &= ~(0x80000000 >> bits);
  1796.         for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  1797.             if(rp->target == target)
  1798.                 return rp;
  1799.         }
  1800.     }
  1801.     if(r_default.interface != NULLIF)
  1802.         return &r_default;
  1803.     else
  1804.         return NULLROUTE;
  1805. }
  1806. /* Internet checksum routines
  1807.  * Improved portability courtesy Rick Spanbauer, WB2CFV
  1808.  */
  1809. #define SLOWCHECK
  1810. #ifdef SLOWCHECK
  1811. /*
  1812.  * Word aligned linear buffer checksum routine.  Called from mbuf checksum
  1813.  * routine with simple args.  Intent is that this routine may be replaced
  1814.  * by assembly language routine for speed if so desired.
  1815.  */
  1816. static int16
  1817. lcsum(sum, wp, len)
  1818. register int32 sum;
  1819. register int16 *wp;
  1820. int16 len;
  1821. {
  1822.     register int16 csum;
  1823.  
  1824.     while(len-- != 0)
  1825.         sum += *wp++;
  1826.     while((csum = sum >> 16) != 0)
  1827.         sum = csum + (sum & 0xffff);
  1828.     return sum & 0xffff;
  1829. }
  1830. #endif SLOWCHECK
  1831.  
  1832. /* Perform end-around-carry adjustment */
  1833. static int16
  1834. eac(sum)
  1835. register int32 sum;    /* Carries in high order 16 bits */
  1836. {
  1837.     register int16 csum;
  1838.  
  1839.     while((csum = sum >> 16) != 0)
  1840.         sum = csum + (sum & 0xffff);
  1841.     return sum;    /* Chops to 16 bits */
  1842. }
  1843. /* Checksum a mbuf chain, with optional pseudo-header */
  1844. int16
  1845. cksum(ph,m,len)
  1846. struct pseudo_header *ph;
  1847. register struct mbuf *m;
  1848. int16 len;
  1849. {
  1850.     register unsigned int cnt, total;
  1851.     register int32 sum, csum;
  1852.     register unsigned char *up;
  1853.  
  1854.     sum = 0l;
  1855.  
  1856.     /* Sum pseudo-header, if present */
  1857.     if(ph != NULLHEADER){
  1858.         sum = hiword(ph->source);
  1859.         sum += loword(ph->source);
  1860.         sum += hiword(ph->dest);
  1861.         sum += loword(ph->dest);
  1862.         sum += ph->protocol & 0xff;
  1863.         sum += ph->length;
  1864.         /* Swapping the sum is equivalent to summing the swapped
  1865.          * elements, but faster. Do end-around-carry first.
  1866.          */
  1867.         sum = htons(eac(sum));
  1868.     }
  1869.     /* Now do each mbuf on the chain */
  1870.     for(total = 0; m != NULLBUF && total < len; m = m->next) {
  1871.         cnt = min(m->cnt, len - total);
  1872.         up = (unsigned char *)m->data;
  1873.  
  1874.         /* Handle odd leading byte */
  1875.         if(((long)up) & 1){
  1876.             csum = (int16)ntohs(*up++);
  1877.             cnt--;
  1878.         } else
  1879.             csum = 0;
  1880.  
  1881.         /* Handle odd trailing byte */
  1882.         if(cnt & 1)
  1883.             csum += (int16)ntohs(up[--cnt]<<8);
  1884.  
  1885.         if(cnt != 0){
  1886.             /* Have the primitive checksumming routine do most of
  1887.              * the work. At this point, up is guaranteed to be on
  1888.              * a short boundary and cnt is guaranteed to be even
  1889.              */
  1890.             csum = lcsum(csum, (unsigned short *)up, cnt >> 1);
  1891.         }
  1892.         /* If the mbuf we just did wasn't on a word boundary within
  1893.          * the whole packet, then byteswap the checksum for this mbuf
  1894.          */
  1895.         if((total&1) ^ (((long)m->data)&1)){
  1896.             csum = eac(csum);
  1897.             csum = (csum >> 8) + ((csum&0xff) << 8);
  1898.         }
  1899.         sum += csum;
  1900.         total += m->cnt;
  1901.     } 
  1902.     /* Do final end-around carry, complement and return */
  1903.     return ~eac(sum) & 0xffff;
  1904. }
  1905. #ifdef    TRACE
  1906. #include "trace.h"
  1907.  
  1908. void
  1909. ip_dump(bp)
  1910. struct mbuf *bp;
  1911. {
  1912.     void tcp_dump(),udp_dump(),icmp_dump();
  1913.     register struct ip_header *ip;
  1914.     int32 source,dest;
  1915.     int16 ip_len;
  1916.     int16 length;
  1917.     struct mbuf *tbp;
  1918.     int16 offset;
  1919.     int i;
  1920.     int check;
  1921.     char tmpbuf;    
  1922.  
  1923.     if(bp == NULLBUF)
  1924.         return;    
  1925.  
  1926.     /* If packet isn't in a single buffer, make a temporary copy and
  1927.      * note the fact so we free it later
  1928.      */
  1929.     if(bp->next != NULLBUF){
  1930.         bp = copy_p(bp,len_mbuf(bp));
  1931.         tmpbuf = 1;
  1932.     } else
  1933.         tmpbuf = 0;
  1934.  
  1935.     ip = (struct ip_header *)bp->data;
  1936.     ip_len = lonibble(ip->v_ihl) * sizeof(int32);
  1937.     length = ntohs(ip->length);
  1938.     offset = (ntohs(ip->fl_offs) & F_OFFSET) << 3 ;
  1939.     source = ntohl(ip->source);
  1940.     dest = ntohl(ip->dest);
  1941.     printf("IP: %s",inet_ntoa(source));
  1942.     printf("->%s len %u ihl %u ttl %u prot %u",
  1943.         inet_ntoa(dest),length,ip_len,ip->ttl & 0xff,
  1944.         ip->protocol & 0xff);
  1945.  
  1946.     if(ip->tos != 0)
  1947.         printf(" tos %u",ip->tos);
  1948.     if(offset != 0 || (ntohs(ip->fl_offs) & MF))
  1949.         printf(" id %u offs %u",ntohs(ip->id),offset);
  1950.  
  1951.     if(ntohs(ip->fl_offs) & DF)
  1952.         printf(" DF");
  1953.     if(ntohs(ip->fl_offs) & MF){
  1954.         printf(" MF");
  1955.         check = 0;    /* Bypass host-level checksum verify */
  1956.     } else {
  1957.         check = 1;
  1958.     }
  1959.  
  1960.     if((i = cksum(NULLHEADER,bp,ip_len)) != 0)
  1961.         printf(" CHECKSUM ERROR (%u)",i);
  1962.     printf("\r\n");
  1963.  
  1964.     if((trace & TRACE_HDR) > 3){
  1965.         if(offset == 0){
  1966.             dup_p(&tbp,bp,ip_len,length - ip_len);
  1967.             switch(ip->protocol & 0xff){
  1968.             case TCP_PTCL:
  1969.                 tcp_dump(tbp,source,dest,check);
  1970.                 break;
  1971.             case UDP_PTCL:
  1972.                 udp_dump(tbp,source,dest,check);
  1973.                 break;
  1974.             case ICMP_PTCL:
  1975.                 icmp_dump(tbp,source,dest,check);
  1976.                 break;
  1977.             }
  1978.             free_p(tbp);
  1979.         }
  1980.     }
  1981.     if(tmpbuf)
  1982.         free_p(bp);
  1983.     fflush(stdout);
  1984. }
  1985. /* Dump IP routing table
  1986.  * Dest              Length    Interface    Gateway          Metric
  1987.  * 192.001.002.003   32        sl0          192.002.003.004       4
  1988.  */
  1989. int
  1990. dumproute()
  1991. {
  1992.     register unsigned int i,bits;
  1993.     register struct route *rp;
  1994.  
  1995.     printf("Dest              Length    Interface    Gateway          Metric\r\n");
  1996.     if(r_default.interface != NULLIF){
  1997.         printf("default           0         %-13s",
  1998.          r_default.interface->name);
  1999.         if(r_default.gateway != 0)
  2000.             printf("%-17s",inet_ntoa(r_default.gateway));
  2001.         else
  2002.             printf("%-17s","");
  2003.         printf("%6u\r\n",r_default.metric);
  2004.     }
  2005.     for(bits=1;bits<=32;bits++){
  2006.         for(i=0;i<NROUTE;i++){
  2007.             for(rp = routes[bits-1][i];rp != NULLROUTE;rp = rp->next){
  2008.                 printf("%-18s",inet_ntoa(rp->target));
  2009.                 printf("%-10u",bits);
  2010.                 printf("%-13s",rp->interface->name);
  2011.                 if(rp->gateway != 0)
  2012.                     printf("%-17s",inet_ntoa(rp->gateway));
  2013.                 else
  2014.                     printf("%-17s","");
  2015.                 printf("%6u\r\n",rp->metric);
  2016.             }
  2017.         }
  2018.     }
  2019.     return 0;
  2020. }
  2021. #endif
  2022. SHAR_EOF
  2023. cat << \SHAR_EOF > telnetp.c
  2024. #include <stdio.h>
  2025. #include <exec/types.h>
  2026. #include <exec/nodes.h>
  2027. #include <exec/lists.h>
  2028. #include <exec/tasks.h>
  2029. #include <exec/ports.h>
  2030. #include <exec/libraries.h>
  2031. #include <exec/io.h>
  2032. #include <exec/devices.h>
  2033. #include <exec/errors.h>
  2034. #include <proto/exec.h>
  2035. #include <devices/console.h>
  2036. #include <libraries/dos.h>
  2037. #include <libraries/dosextens.h>
  2038. #include <intuition/intuition.h>
  2039. #include <dos.h>
  2040. #include "machdep.h"
  2041. #include "mbuf.h"
  2042. #include "timer.h"
  2043. #include "internet.h"
  2044. #include "icmp.h"
  2045. #include "netuser.h"
  2046. #include "tcp.h"
  2047. #include "telnet.h"
  2048. #include "session.h"
  2049. #include "inetdev.h"
  2050. #include "inetlib.h"
  2051. #define DEBUG
  2052. struct Process *mytask;
  2053. APTR    oldwindowptr;
  2054. struct IntuitionBase *IntuitionBase;
  2055. char banner[80] = "telnet window";
  2056. static struct NewWindow nw = {
  2057.     0, 0, 640, 200,        /* left, top, (max) width, (max) height */
  2058.     0, 1,            /* detail pen, block pen */
  2059.     0,            /* IDCMP flags */
  2060.     SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING |
  2061.         SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH,    /* window flags */
  2062.     NULL, NULL,        /* gadget, checkmark */
  2063.     (UBYTE *)&banner[0],    /* title of window */
  2064.     NULL, NULL,        /* screen, bitmap */
  2065.     200, 50, -1, -1,    /* sizing limits */
  2066.     WBENCHSCREEN,        /* on the workbench */
  2067. };
  2068. struct Window *win;
  2069. struct MsgPort *keyboard, *consinp, *consoutp, *tcpinp, *tcpoutp;
  2070. struct IOStdReq consin, consout;
  2071. char InputCharacter;
  2072. int deviceopened = 0;
  2073. struct IOINETReq tnreq, tninreq, tnoutreq;
  2074. char recv[512], snd[512];
  2075. struct telnet *tn;
  2076. #ifdef LATTICE
  2077. extern struct { short error; char *msg; } os_errlist[];
  2078. extern int _OSERR, os_nerr;
  2079. #endif
  2080. static
  2081. clean(why)
  2082.     char *why;
  2083. {
  2084.     int i;
  2085.     InputCharacter = ' ';
  2086.         while (InputCharacter != '<')
  2087.       if (kbread() > 0)
  2088.         amigaputchar(InputCharacter);
  2089.  
  2090.     if (win)
  2091.         CloseWindow(win);
  2092.     if (consinp)
  2093.         DeletePort(consinp);
  2094.     if (consoutp)
  2095.         DeletePort(consoutp);
  2096.     if (tcpinp)
  2097.         DeletePort(tcpinp);
  2098.     if (tcpoutp)
  2099.         DeletePort(tcpoutp);
  2100.     if (deviceopened)
  2101.         CloseDevice(&tnreq);
  2102.     mytask->pr_WindowPtr = oldwindowptr;
  2103.     if (why) {
  2104.            myoserr(why);
  2105.     }
  2106.     exit(0);
  2107. }
  2108. printlist(l)
  2109. struct List *l;
  2110. {
  2111.   printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail, 
  2112.         l->lh_TailPred);
  2113. }
  2114. myoserr(why)
  2115. char *why;
  2116. {
  2117.   int i;
  2118.         fprintf(stderr, "%s: ", why); 
  2119. #ifdef LATTICE
  2120.         fprintf(stderr, "%d: ", _OSERR);
  2121.  
  2122.         for(i = 0; os_errlist[i].error < os_nerr; i++)
  2123.           if (os_errlist[i].error == _OSERR)
  2124.             fprintf(stderr, os_errlist[i].msg);
  2125. #endif
  2126.         fprintf(stderr, "\r\n");
  2127. }
  2128. /* Called at startup time to set up console I/O, memory heap */
  2129. ioinit()
  2130. {
  2131.     struct Screen *scr;
  2132.  
  2133.     mytask = (struct Process *) FindTask((char *) NULL);
  2134.     oldwindowptr = mytask->pr_WindowPtr;
  2135.     mytask->pr_WindowPtr = (APTR) -1;    /* disable DOS requestors */
  2136.  
  2137.     if ((IntuitionBase = (struct IntuitionBase *)
  2138.        OpenLibrary("intuition.library", 33L)) == NULL)
  2139.         clean("No intuition: Version 1.2 of Amiga Systems Software required");
  2140.     /*
  2141.      *  Try to determine the size of the workbench screen
  2142.      */
  2143.     scr = malloc(sizeof(struct Screen));
  2144.     if (scr==NULL)
  2145.         clean("Can't alloc screen");
  2146.  
  2147.     if (GetScreenData(scr, (ULONG) sizeof(struct Screen),
  2148.               WBENCHSCREEN, NULL) == TRUE) {
  2149.         nw.Width = scr->Width;
  2150.         nw.Height = scr->Height-20;
  2151.         nw.TopEdge = 19;
  2152.     } else
  2153.         fprintf(stderr, "Can't GetScreenData()\n");
  2154.  
  2155.     free((char *)scr);
  2156.     if ((win = OpenWindow(&nw)) == NULL)
  2157.         clean("Can't open window");
  2158.     if ((consinp = CreatePort("telnet:console in", 0L)) == NULL)
  2159.         clean("Can't create console port");
  2160.     if ((tcpinp = CreatePort("telnet:tcp in", 0L)) == NULL)
  2161.         clean("Can't create telnet tcp input port");
  2162.     if ((tcpoutp = CreatePort("telnet:tcp out", 0L)) == NULL)
  2163.         clean("Can't create telnet tcp output port");
  2164.  
  2165.     consin.io_Data = (APTR) win;
  2166.     consin.io_Length = sizeof(struct Window);
  2167.  
  2168.     _OSERR = OpenDevice("console.device", 0L, &consin, 0L);
  2169.     if (_OSERR != 0L){
  2170.         printf("opendevice returned %d\n", _OSERR);
  2171.         myoserr("could not get console");
  2172.         clean("Can't open console device");
  2173.     }
  2174.     consout = consin;
  2175.  
  2176.     consin.io_Message.mn_ReplyPort = consinp;
  2177.     consin.io_Length = 1;
  2178.     consin.io_Data = (APTR) &InputCharacter;
  2179.     consin.io_Command = CMD_READ;
  2180.     SendIO(&consin);
  2181.     consout.io_Message.mn_ReplyPort = consoutp;
  2182.     consout.io_Command = CMD_WRITE;
  2183.  
  2184.  
  2185. }
  2186. /* Read characters from the keyboard, translating them to "real" ASCII
  2187.  * If none are ready, return the -1 from kbraw()
  2188.  */
  2189. kbread()
  2190. {
  2191.     char c;
  2192.  
  2193.     if (CheckIO(&consin)) {
  2194.         WaitIO(&consin);
  2195.         c = InputCharacter;
  2196.         consin.io_Length = 1;
  2197.         consin.io_Data = (APTR) &InputCharacter;
  2198.         consin.io_Command = CMD_READ;
  2199.         SendIO(&consin);        /* start next read up */
  2200.         return (c & 0xff);
  2201.     }
  2202.  
  2203.     return -1;        /* nuthin here */
  2204. }
  2205. extern char nospace[];
  2206. int refuse_echo = 0;
  2207. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  2208.  
  2209. #ifdef    DEBUG
  2210. char *t_options[] = {
  2211.     "Transmit Binary",
  2212.     "Echo",
  2213.     "",
  2214.     "Suppress Go Ahead",
  2215.     "",
  2216.     "Status",
  2217.     "Timing Mark"
  2218. };
  2219. #endif
  2220. /* Telnet receiver upcall routine */
  2221. void
  2222. rcv_char()
  2223. {
  2224. /*printf("rcv_char: %d\n", tninreq.io_Actual);*/
  2225.     tel_input(tn,tninreq.io_Data, tninreq.io_Actual);
  2226.  
  2227.     fflush(stdout);
  2228. }
  2229. brk()
  2230. {
  2231.   clean("ok i iwll quit\n");
  2232. }
  2233. /* TCP connection states */
  2234. char *tcpstates[] = {
  2235.     "Closed",
  2236.     "Listen",
  2237.     "SYN sent",
  2238.     "SYN received",
  2239.     "Established",
  2240.     "FIN wait 1",
  2241.     "FIN wait 2",
  2242.     "Close wait",
  2243.     "Closing",
  2244.     "Last ACK",
  2245.     "Time wait"
  2246. };
  2247. /* TCP segment header flags */
  2248. char *tcpflags[] = {
  2249.     "FIN",    /* 0x01 */
  2250.     "SYN",    /* 0x02 */
  2251.     "RST",    /* 0x04 */
  2252.     "PSH",    /* 0x08 */
  2253.     "ACK",    /* 0x10 */
  2254.     "URG"    /* 0x20 */
  2255. };
  2256.  
  2257. /* TCP closing reasons */
  2258. char *reasons[] = {
  2259.     "Normal",
  2260.     "Reset",
  2261.     "Timeout",
  2262.     "ICMP"
  2263. };
  2264. char old = LISTEN;
  2265. int done = 0;
  2266. char *hostname="";
  2267. int hostport=0;
  2268. char *bannerfmt = "telnet %10s %4d %10s";
  2269. void
  2270. showstate(old, new)
  2271.     char old, new;
  2272. {
  2273.  
  2274.  
  2275. /*    extern char *tcpstates[];
  2276.     extern char *reasons[];
  2277.     extern char *unreach[];
  2278.     extern char *exceed[];
  2279. */
  2280.     /* Can't add a check for unknown connection here, it would loop
  2281.      * on a close upcall! We're just careful later on.
  2282.      */
  2283.  
  2284.     sprintf(banner, bannerfmt, hostname, hostport, tcpstates[new]);
  2285.     SetWindowTitles(win, banner, -1);
  2286.     switch(new){
  2287.     case CLOSE_WAIT:
  2288.         done = 1;
  2289.         break;
  2290.     case CLOSED:    /* court adjourned */
  2291. /*            printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  2292.             if(tcb->reason == NETWORK){
  2293.                 switch(tcb->type){
  2294.                 case DEST_UNREACH:
  2295.                     printf(": %s unreachable",unreach[tcb->code]);
  2296.                     break;
  2297.                 case TIME_EXCEED:
  2298.                     printf(": %s time exceeded",exceed[tcb->code]);
  2299.                     break;
  2300.                 }
  2301.             }
  2302.             printf(")\r\n");
  2303. */
  2304.         done = 1;
  2305.         break;
  2306.     default:
  2307.         break;
  2308.     }
  2309.     fflush(stdout);
  2310.  
  2311. }
  2312.  
  2313. /* Execute user telnet command */
  2314. main(argc,argv)
  2315. int argc;
  2316. char *argv[];
  2317. {
  2318.     extern int _OSERR;
  2319.     struct InternetBase *InternetBase;
  2320.     int send_tel();
  2321.         int unix_send_tel();
  2322.     struct session *s;
  2323.  
  2324. /*    struct tcb *tcb = NULL;*/
  2325.     struct socket lsocket,fsocket;
  2326.     ioinit();
  2327.     hostname = argv[1];
  2328.     old = LISTEN;
  2329.     showstate(old, LISTEN);
  2330.     tnreq.io_fsocket.address = aton(argv[1]);
  2331.     if(argc < 3)
  2332.         tnreq.io_fsocket.port = TELNET_PORT;
  2333.     else
  2334.         tnreq.io_fsocket.port = atoi(argv[2]);
  2335.     tnreq.io_Device = NULL;
  2336.     tnreq.io_Unit = NULL;
  2337.     tnreq.io_Flags = 0;
  2338.     tnreq.io_Error = 0;
  2339.     InternetBase = (struct InternetBase *) OpenDevice("internet.device",
  2340.                 (long) INET_UNIT_TCP, &tnreq, 0L);
  2341.     if (InternetBase != 0L){
  2342.       printf("it did not open %d\n",InternetBase);
  2343.       clean("i quit");
  2344.     }
  2345. /*    tcb = (struct tcb *) tnreq.io_Unit->iu_ccb;*/
  2346.  
  2347.     hostport = tnreq.io_lsocket.port;
  2348.     deviceopened = 1;
  2349.     tninreq = tnreq; /* possible lettuce bug  ?*/
  2350.     tnoutreq = tnreq;
  2351.     tninreq.io_Length = 512;
  2352.     tnoutreq.io_Length = 1;
  2353.     tninreq.io_Data = recv;
  2354.     tnoutreq.io_Data = &InputCharacter;
  2355.     tninreq.io_Command = CMD_READ;
  2356.     tnoutreq.io_Command = CMD_WRITE;
  2357.     tninreq.io_Message.mn_ReplyPort = tcpinp;
  2358.     tnoutreq.io_Message.mn_ReplyPort = tcpoutp;
  2359.     /* Create and initialize a Telnet protocol descriptor */
  2360.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  2361.         myoserr("calloc faiuled\n");
  2362.         goto done;
  2363.     }
  2364.     tn->session = s;    /* Upward pointer */
  2365.     tn->state = TS_DATA;
  2366.         SendIO(&tninreq);
  2367.     onbreak(&brk);
  2368.     InputCharacter = ' ';
  2369.     while (! done)
  2370.       {
  2371.         if ((snd[0] = kbread()) >= 0){
  2372.           
  2373.           unix_send_tel(snd, (short) 1);}
  2374.  
  2375.         if (CheckIO(&tninreq))
  2376.           {
  2377.         chkabort();
  2378.         WaitIO(&tninreq);
  2379.             rcv_char();
  2380.             if (tninreq.io_State != old)
  2381.               {
  2382.             showstate(old, tninreq.io_State);
  2383.             old = tninreq.io_State;
  2384.               }
  2385.                 SendIO(&tninreq);
  2386.           }
  2387.       }
  2388. done:
  2389.     clean("All done");          
  2390.  
  2391. #ifdef NOTDEF
  2392.     /* Allocate a session descriptor */
  2393.     if((s = newsession()) == NULLSESSION){
  2394.         printf("Too many sessions\r\n");
  2395.         return 1;
  2396.     }
  2397.     s->type = TELNET;
  2398.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  2399.         s->parse = unix_send_tel;
  2400.     } else {
  2401.         s->parse = send_tel;
  2402.     }
  2403.     current = s;
  2404.  
  2405.     /* Create and initialize a Telnet protocol descriptor */
  2406.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  2407.         printf(nospace);
  2408.         s->type = FREE;
  2409.         return 1;
  2410.     }
  2411.     tn->session = s;    /* Upward pointer */
  2412.     tn->state = TS_DATA;
  2413.     s->cb.telnet = tn;    /* Downward pointer */
  2414.  
  2415.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  2416.      rcv_char,NULLVFP,t_state,0,(int *)tn);
  2417.     if(tcb == NULLTCB || tcb->state == CLOSED){
  2418.         /* This is actually a bit dirty here. About the only time the
  2419.          * state will be closed here is if we tried to connect to
  2420.          * ourselves and got RST'ed.  If this is true then the close
  2421.          * upcall will already have freed the TCB and telnet block,
  2422.          * so we're looking at the TCB after it's back on the heap.
  2423.          */
  2424.         return 0;
  2425.     }
  2426.     tn->tcb = tcb;    /* Downward pointer */
  2427.     go();
  2428.     return 0;
  2429. #endif
  2430. }
  2431.  
  2432. /* Process typed characters */
  2433. int
  2434. unix_send_tel(buf,n)
  2435. char *buf;
  2436. int16 n;
  2437. {
  2438.     int i;
  2439. /*printf("unix_send_tel: buf[0] %d\n", buf[0]);*/
  2440.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  2441.         ;
  2442.     if (buf[i] == '\r') {
  2443.         buf[i] = '\n';
  2444.         n = i+1;
  2445.     }
  2446.     send_tel(buf,n);
  2447. }
  2448. int
  2449. send_tel(buf,n)
  2450. char *buf;
  2451. int16 n;
  2452. {
  2453.     int i;
  2454.  
  2455.     tnoutreq.io_Data = buf;
  2456.     tnoutreq.io_Length = n;
  2457.  
  2458.     SendIO(&tnoutreq);
  2459. /*    printf("now waitio insend_tel: ");*/
  2460.     i = WaitIO(&tnoutreq); 
  2461. /*printf("send_tel: WaitIo is %d\n", i);*/
  2462.     if (tnoutreq.io_State != old)
  2463.       {
  2464.         showstate(old, tnoutreq.io_State);
  2465.         old = tnoutreq.io_State;
  2466.       }
  2467.  
  2468. }
  2469.  
  2470. /* Process incoming TELNET characters */
  2471. int
  2472. tel_input(tn,bp, len)
  2473. register struct telnet *tn;
  2474. char *bp;
  2475. int len;
  2476. {
  2477.     char c;
  2478.     int ci;
  2479.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  2480. #ifdef    FAST    /* DON'T USE -- Aztec memchr() routine is broken */
  2481.     char *memchr();
  2482.  
  2483.     /* Optimization for very common special case -- no command chars */
  2484.     if(tn->state == TS_DATA){
  2485.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) 
  2486.             == NULLCHAR){
  2487.             fflush(stdout);
  2488.             write(1,bp->data,bp->cnt);
  2489.             bp = free_mbuf(bp);
  2490.         }
  2491.     }
  2492. #endif
  2493.     while(len--){
  2494.         c = *bp++;
  2495.         ci = c & 0xff;
  2496.         switch(tn->state){
  2497.         case TS_DATA:
  2498.             if(ci == IAC){
  2499.                 tn->state = TS_IAC;
  2500.             } else {
  2501.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  2502.                     c &= 0x7f;
  2503.                 putchar(c);
  2504.             }
  2505.             break;
  2506.         case TS_IAC:
  2507.             switch(ci){
  2508.             case WILL:
  2509.                 tn->state = TS_WILL;
  2510.                 break;
  2511.             case WONT:
  2512.                 tn->state = TS_WONT;
  2513.                 break;
  2514.             case DO:
  2515.                 tn->state = TS_DO;
  2516.                 break;
  2517.             case DONT:
  2518.                 tn->state = TS_DONT;
  2519.                 break;
  2520.             case IAC:
  2521.                 putchar(c);
  2522.                 tn->state = TS_DATA;
  2523.                 break;
  2524.             default:
  2525.                 tn->state = TS_DATA;
  2526.                 break;
  2527.             }
  2528.             break;
  2529.         case TS_WILL:
  2530.             willopt(tn,ci);
  2531.             tn->state = TS_DATA;
  2532.             break;
  2533.         case TS_WONT:
  2534.             wontopt(tn,ci);
  2535.             tn->state = TS_DATA;
  2536.             break;
  2537.         case TS_DO:
  2538.             doopt(tn,ci);
  2539.             tn->state = TS_DATA;
  2540.             break;
  2541.         case TS_DONT:
  2542.             dontopt(tn,ci);
  2543.             tn->state = TS_DATA;
  2544.             break;
  2545.         }
  2546.     }
  2547. }
  2548.  
  2549. #ifdef NOTDEF
  2550. /* State change upcall routine */
  2551. void
  2552. t_state(tcb,old,new)
  2553. register struct tcb *tcb;
  2554. char old,new;
  2555. {
  2556.     struct telnet *tn;
  2557.     char notify = 0;
  2558.     extern char *tcpstates[];
  2559.     extern char *reasons[];
  2560.     extern char *unreach[];
  2561.     extern char *exceed[];
  2562.  
  2563.     /* Can't add a check for unknown connection here, it would loop
  2564.      * on a close upcall! We're just careful later on.
  2565.      */
  2566.     tn = (struct telnet *)tcb->user;
  2567.  
  2568.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  2569.         notify = 1;
  2570.  
  2571.     switch(new){
  2572.     case CLOSE_WAIT:
  2573.         if(notify)
  2574.             printf("%s\r\n",tcpstates[new]);
  2575.         close_tcp(tcb);
  2576.         break;
  2577.     case CLOSED:    /* court adjourned */
  2578.         if(notify){
  2579.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  2580.             if(tcb->reason == NETWORK){
  2581.                 switch(tcb->type){
  2582.                 case DEST_UNREACH:
  2583.                     printf(": %s unreachable",unreach[tcb->code]);
  2584.                     break;
  2585.                 case TIME_EXCEED:
  2586.                     printf(": %s time exceeded",exceed[tcb->code]);
  2587.                     break;
  2588.                 }
  2589.             }
  2590.             printf(")\r\n");
  2591.             cmdmode();
  2592.         }
  2593.         del_tcp(tcb);
  2594.         if(tn != NULLTN)
  2595.             free_telnet(tn);
  2596.         break;
  2597.     default:
  2598.         if(notify)
  2599.             printf("%s\r\n",tcpstates[new]);
  2600.         break;
  2601.     }
  2602.     fflush(stdout);
  2603. }
  2604. #endif
  2605. /* Delete telnet structure */
  2606. static
  2607. free_telnet(tn)
  2608. struct telnet *tn;
  2609. {
  2610.  
  2611.     if(tn != NULLTN)
  2612.         free((char *)tn);
  2613. }
  2614.  
  2615. /* The guts of the actual Telnet protocol: negotiating options */
  2616. static
  2617. void
  2618. willopt(tn,opt)
  2619. struct telnet *tn;
  2620. int opt;
  2621. {
  2622.     int ack;
  2623.     void answer();
  2624.  
  2625. #ifdef    DEBUG
  2626.     printf("recv: will ");
  2627.     if(opt <= NOPTIONS)
  2628.         printf("%s\r\n",t_options[opt]);
  2629.     else
  2630.         printf("%u\r\n",opt);
  2631. #endif
  2632.     
  2633.     switch(opt){
  2634.     case TN_TRANSMIT_BINARY:
  2635.     case TN_ECHO:
  2636.     case TN_SUPPRESS_GA:
  2637.         if(tn->remote[opt] == 1)
  2638.             return;        /* Already set, ignore to prevent loop */
  2639.         if(opt == TN_ECHO){
  2640.             if(refuse_echo){
  2641.                 /* User doesn't want to accept */
  2642.                 ack = DONT;
  2643.                 break;
  2644.             } else
  2645.                 raw();        /* Put tty into raw mode */
  2646.         }
  2647.         tn->remote[opt] = 1;
  2648.         ack = DO;            
  2649.         break;
  2650.     default:
  2651.         ack = DONT;    /* We don't know what he's offering; refuse */
  2652.     }
  2653.     answer(tn,ack,opt);
  2654. }
  2655. static
  2656. void
  2657. wontopt(tn,opt)
  2658. struct telnet *tn;
  2659. int opt;
  2660. {
  2661.     void answer();
  2662.  
  2663. #ifdef    DEBUG
  2664.     printf("recv: wont ");
  2665.     if(opt <= NOPTIONS)
  2666.         printf("%s\r\n",t_options[opt]);
  2667.     else
  2668.         printf("%u\r\n",opt);
  2669. #endif
  2670.     if(opt <= NOPTIONS){
  2671.         if(tn->remote[opt] == 0)
  2672.             return;        /* Already clear, ignore to prevent loop */
  2673.         tn->remote[opt] = 0;
  2674.         if(opt == TN_ECHO)
  2675.             cooked();    /* Put tty into cooked mode */
  2676.     }
  2677.     answer(tn,DONT,opt);    /* Must always accept */
  2678. }
  2679. static
  2680. void
  2681. doopt(tn,opt)
  2682. struct telnet *tn;
  2683. int opt;
  2684. {
  2685.     void answer();
  2686.     int ack;
  2687.  
  2688. #ifdef    DEBUG
  2689.     printf("recv: do ");
  2690.     if(opt <= NOPTIONS)
  2691.         printf("%s\r\n",t_options[opt]);
  2692.     else
  2693.         printf("%u\r\n",opt);
  2694. #endif
  2695.     switch(opt){
  2696. #ifdef    FUTURE    /* Use when local options are implemented */
  2697.         if(tn->local[opt] == 1)
  2698.             return;        /* Already set, ignore to prevent loop */
  2699.         tn->local[opt] = 1;
  2700.         ack = WILL;
  2701.         break;
  2702. #endif
  2703.     default:
  2704.         ack = WONT;    /* Don't know what it is */
  2705.     }
  2706.     answer(tn,ack,opt);
  2707. }
  2708. static
  2709. void
  2710. dontopt(tn,opt)
  2711. struct telnet *tn;
  2712. int opt;
  2713. {
  2714.     void answer();
  2715.  
  2716. #ifdef    DEBUG
  2717.     printf("recv: dont ");
  2718.     if(opt <= NOPTIONS)
  2719.         printf("%s\r\n",t_options[opt]);
  2720.     else
  2721.         printf("%u\r\n",opt);
  2722. #endif
  2723.     if(opt <= NOPTIONS){
  2724.         if(tn->local[opt] == 0){
  2725.             /* Already clear, ignore to prevent loop */
  2726.             return;
  2727.         }
  2728.         tn->local[opt] = 0;
  2729.     }
  2730.     answer(tn,WONT,opt);
  2731. }
  2732. static
  2733. void
  2734. answer(tn,r1,r2)
  2735. struct telnet *tn;
  2736. int r1,r2;
  2737. {
  2738.     struct mbuf *bp,*qdata();
  2739.     char s[3];
  2740.  
  2741. #ifdef    DEBUG
  2742.     switch(r1){
  2743.     case WILL:
  2744.         printf("sent: will ");
  2745.         break;
  2746.     case WONT:
  2747.         printf("sent: wont ");
  2748.         break;
  2749.     case DO:
  2750.         printf("sent: do ");
  2751.         break;
  2752.     case DONT:
  2753.         printf("sent: dont ");
  2754.         break;
  2755.     }
  2756.     if(r2 <= 6)
  2757.         printf("%s\r\n",t_options[r2]);
  2758.     else
  2759.         printf("%u\r\n",r2);
  2760. #endif
  2761.  
  2762.     s[0] = IAC;
  2763.     s[1] = r1;
  2764.     s[2] = r2;
  2765.     tnoutreq.io_Data = s;
  2766.     tnoutreq.io_Length = 3;
  2767.     DoIO(&tnoutreq);
  2768. /*
  2769.     bp = qdata(s,(int16)3);
  2770.     send_tcp(tn->tcb,bp);
  2771. */
  2772. }
  2773.  
  2774. #define    BUFMAXCNT    150
  2775. static char conbuf[BUFMAXCNT];
  2776. static int concnt = 0;
  2777.  
  2778. int
  2779. amigaputchar(c)
  2780.     char c;
  2781. {
  2782.     conbuf[concnt++] = c;
  2783.     if ((c == '\n') || (concnt == BUFMAXCNT))
  2784.         amigaflush();
  2785.     return c;
  2786. }
  2787.  
  2788. amigaflush()
  2789. {
  2790.     if (concnt == 0)
  2791.         return;
  2792.     consout.io_Data = (APTR) conbuf;
  2793.     consout.io_Length = concnt;
  2794.     consout.io_Command = CMD_WRITE;
  2795.     DoIO(&consout);
  2796.     concnt = 0;
  2797. }
  2798.     
  2799. /*
  2800.  *  Begin terrible, horrible hack.  All output should be printed upon (into?)
  2801.  *  the window we opened before.  Here goes nothing...
  2802.  */
  2803.  
  2804. printf(a, b, c, d, e, f, g, h, i, j, k)
  2805.     char *a;
  2806.     int b, c, d, e, f, g, h, i, j, k;
  2807. {
  2808.     if (concnt)
  2809.         amigaflush();
  2810.  
  2811.     sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k);
  2812.     consout.io_Data = (APTR) conbuf;
  2813.     consout.io_Length = strlen(conbuf);
  2814.     consout.io_Command = CMD_WRITE;
  2815.     DoIO(&consout);        /* no use in doing this async */
  2816. }
  2817. SHAR_EOF
  2818. #    End of shell archive
  2819. exit 0
  2820. -- 
  2821. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2822. Have five nice days.
  2823.